/*=============================================================================
ShaderFXParseBin.cpp : implementation of the Shaders parser using FX language.
Copyright (c) 2001-2004 Crytek Studios. All Rights Reserved.

Revision history:
* Created by Honich Andrey

=============================================================================*/

#include "StdAfx.h"

#include <IPlatformOS.h>

static FOURCC FOURCC_SHADERBIN = MAKEFOURCC('F','X','B','0');

namespace 
{ 
	static std::vector<SFXParam> s_tempFXParams;
} 

SShaderBin SShaderBin::m_Root;
uint32 SShaderBin::m_nCache = 0;
uint32 SShaderBin::m_nMaxFXBinCache = MAX_FXBIN_CACHE;
CShaderManBin::CShaderManBin()
{
  m_pCEF = &gRenDev->m_cEF;
}

int CShaderManBin::Size()
{
	 SShaderBin *pSB;
  int nSize = 0;
	nSize += sizeOfMapStr(m_BinPaths); 
	nSize += m_BinValidCRCs.size() * sizeof(bool) * sizeof(stl::MapLikeStruct);

  for (pSB=SShaderBin::m_Root.m_Prev; pSB!=&SShaderBin::m_Root; pSB=pSB->m_Prev)
  {
    nSize += pSB->Size();
  }
  return nSize;
}

void CShaderManBin::GetMemoryUsage(ICrySizer *pSizer ) const
{
	pSizer->AddObject(m_BinPaths);
	pSizer->AddObject(m_BinValidCRCs);
	
	SShaderBin *pSB;
	for (pSB=SShaderBin::m_Root.m_Prev; pSB!=&SShaderBin::m_Root; pSB=pSB->m_Prev)
	{
		pSB->GetMemoryUsage(pSizer);
	}	
}

void SShaderBin::CryptData()
{
  uint32 i;
  uint32 *pData = &m_Tokens[0];
  uint32 CRC32 = m_CRC32;
  for (i=0; i<m_Tokens.size(); i++)
  {
    pData[i] ^= CRC32;
  }
}

uint32 SShaderBin::ComputeCRC()
{
  if (!m_Tokens.size())
    return 0;
  uint32 CRC32;
  if (CParserBin::m_bEndians)
  {
    DWORD *pT = new DWORD [m_Tokens.size()];
    memcpy(pT, &m_Tokens[0], m_Tokens.size()*sizeof(uint32));
    SwapEndian(pT, m_Tokens.size(), eBigEndian);
    CRC32 = GetCRC32Gen().GetCRC32((char *)pT, m_Tokens.size()*sizeof(uint32), 0xffffffff);
    delete [] pT;
  }
  else
    CRC32 = GetCRC32Gen().GetCRC32((char *)&m_Tokens[0], m_Tokens.size()*sizeof(uint32), 0xffffffff);
  int nCur = 0;
  Lock();
  while (nCur >= 0)
  {
    nCur = CParserBin::FindToken(nCur, m_Tokens.size()-1, &m_Tokens[0], eT_include);
    if (nCur >= 0)
    {
      nCur++;
      uint32 nTokName = m_Tokens[nCur];
      const char *szNameInc = CParserBin::GetString(nTokName, m_TokenTable);
      SShaderBin *pBinIncl = gRenDev->m_cEF.m_Bin.GetBinShader(szNameInc, true, 0);
      assert(pBinIncl);
      if (pBinIncl)
      {
        CRC32 += pBinIncl->ComputeCRC();
      }
    }
  }
  Unlock();

  return CRC32;
}

SShaderBin *CShaderManBin::SaveBinShader(
	uint32 nSourceCRC32, const char *szName, bool bInclude, FILE *fpSrc)
{
  SShaderBin *pBin = new SShaderBin;

  CParserBin Parser(pBin);

  gEnv->pCryPak->FSeek(fpSrc, 0, SEEK_END);
  int nSize = gEnv->pCryPak->FTell(fpSrc);
  char *buf = new char [nSize+1];
  char *pBuf = buf;
  buf[nSize] = 0;
  gEnv->pCryPak->FSeek(fpSrc, 0, SEEK_SET);
  gEnv->pCryPak->FRead(buf, nSize, fpSrc);

  RemoveCR(buf);
  const char *kWhiteSpace = " ";

  while (buf && buf[0])
  {
    SkipCharacters (&buf, kWhiteSpace);
    SkipComments (&buf, true);
    if (!buf || !buf[0])
      break;

    char com[1024];
    bool bKey = false;
    uint32 dwToken = CParserBin::NextToken(buf, com, bKey);
    dwToken = Parser.NewUserToken(dwToken, com, false);
    pBin->m_Tokens.push_back(dwToken);

    SkipCharacters (&buf, kWhiteSpace);
    SkipComments (&buf, true);
    if (dwToken >= eT_float && dwToken <= eT_int)
    {

    }
    if (dwToken == eT_fetchinst)
    {
      int nnn = 0;
    }
    else
    if (dwToken == eT_include)
    {
      assert(bKey);
      SkipCharacters(&buf, kWhiteSpace);
      assert(*buf == '"' || *buf == '<');
      char brak = *buf;
      ++buf;
      int n = 0;
      while(*buf != brak)
      {
        if (*buf <= 0x20)
        {
          assert(0);
          break;
        }
        com[n++] = *buf;
        ++buf;
      }
      if (*buf == brak)
        ++buf;
      com[n] = 0;

      fpStripExtension(com, com);

      SShaderBin *pBIncl = GetBinShader(com, true, 0);
      //
			//assert(pBIncl);

      dwToken = CParserBin::fxToken(com, NULL);
      dwToken = Parser.NewUserToken(dwToken, com, false);
      pBin->m_Tokens.push_back(dwToken);
    }
    else
    if (dwToken == eT_if || dwToken == eT_ifdef || dwToken == eT_ifndef)
    {
      bool bFirst = fxIsFirstPass(buf);
      if (!bFirst)
      {
        if (dwToken == eT_if)
          dwToken = eT_if_2;
        else
        if (dwToken == eT_ifdef)
          dwToken = eT_ifdef_2;
        else
          dwToken = eT_ifndef_2;
        pBin->m_Tokens[pBin->m_Tokens.size()-1] = dwToken;
      }
    }
    else
    if (dwToken == eT_define)
    {
      shFill(&buf, com);
      if (com[0] == '%')
        pBin->m_Tokens[pBin->m_Tokens.size()-1] = eT_define_2;
      dwToken = Parser.NewUserToken(eT_unknown, com, false);
      pBin->m_Tokens.push_back(dwToken);

      TArray<char> macro;
      while (*buf == 0x20 || *buf == 0x9) {buf++;}
      while (*buf != 0xa)
      {
        if (*buf == '\\')
        {
          macro.AddElem('\n');
          while (*buf != '\n') {buf++;}
          buf++;
          continue;
        }
        macro.AddElem(*buf);
        buf++;
      }
      macro.AddElem(0);
      int n = macro.Num()-2;
      while (n >= 0 && macro[n] <= 0x20)
      {
        macro[n] = 0;
        n--;
      }
      char *b = &macro[0];
      while (*b)
      {
        SkipCharacters (&b, kWhiteSpace);
        SkipComments (&b, true);
        if (!b[0])
          break;
        bKey = false;
        dwToken = CParserBin::NextToken(b, com, bKey);
        dwToken = Parser.NewUserToken(dwToken, com, false);
        if (dwToken == eT_if || dwToken == eT_ifdef || dwToken == eT_ifndef)
        {
          bool bFirst = fxIsFirstPass(b);
          if (!bFirst)
          {
            if (dwToken == eT_if)
              dwToken = eT_if_2;
            else
            if (dwToken == eT_ifdef)
              dwToken = eT_ifdef_2;
            else
              dwToken = eT_ifndef_2;
          }
        }
        pBin->m_Tokens.push_back(dwToken);
      }
      pBin->m_Tokens.push_back(0);
    }
  }
  if (!pBin->m_Tokens[0])
    pBin->m_Tokens.push_back(eT_skip);

  pBin->SetCRC(pBin->ComputeCRC());
  pBin->m_bReadOnly = false;
  //pBin->CryptData();
  //pBin->CryptTable();

  char nameFile[256];
  sprintf(nameFile, "%s%s.%s", m_pCEF->m_ShadersCache, szName, bInclude ? "cfib" : "cfxb");
  stack_string szDst = stack_string(m_pCEF->m_szUserPath.c_str()) + stack_string(nameFile);
	const char * szFileName = szDst;

  FILE *fpDst = gEnv->pCryPak->FOpen(szFileName, "wb");
  if (fpDst)
  {
    SShaderBinHeader Header;
    Header.m_nTokens = pBin->m_Tokens.size();
    Header.m_Magic = FOURCC_SHADERBIN;
    Header.m_CRC32 = pBin->m_CRC32;
    float fVersion = (float)FX_CACHE_VER;
    Header.m_VersionLow = (uint16)(((float)fVersion - (float)(int)fVersion)*10.1f);
    Header.m_VersionHigh = (uint16)fVersion;
    Header.m_nOffsetStringTable = pBin->m_Tokens.size() * sizeof(DWORD) + sizeof(Header);
    Header.m_nOffsetParamsLocal = 0;
		Header.m_nSourceCRC32 = nSourceCRC32;
    SShaderBinHeader hdTemp, *pHD;
    pHD = &Header;
    if (CParserBin::m_bEndians)
    {
      hdTemp = Header;
      SwapEndian(hdTemp, eBigEndian);
      pHD = &hdTemp;
    }
    gEnv->pCryPak->FWrite((void *)pHD, sizeof(Header), 1, fpDst);
    if (CParserBin::m_bEndians)
    {
      DWORD *pT = new DWORD [pBin->m_Tokens.size()];
      memcpy(pT, &pBin->m_Tokens[0], pBin->m_Tokens.size()*sizeof(DWORD));
      SwapEndian(pT, pBin->m_Tokens.size(), eBigEndian);
      gEnv->pCryPak->FWrite((void *)pT, pBin->m_Tokens.size()*sizeof(DWORD), 1, fpDst);
      delete [] pT;
    }
    else
      gEnv->pCryPak->FWrite(&pBin->m_Tokens[0], pBin->m_Tokens.size() * sizeof(DWORD), 1, fpDst);
    FXShaderTokenItor itor;
    for (itor=pBin->m_TokenTable.begin(); itor!=pBin->m_TokenTable.end(); itor++)
    {
      STokenD T = *itor;
      if (CParserBin::m_bEndians)
        SwapEndian(T.Token, eBigEndian);
      gEnv->pCryPak->FWrite(&T.Token, sizeof(DWORD), 1, fpDst);
      gEnv->pCryPak->FWrite(T.SToken.c_str(), T.SToken.size()+1, 1, fpDst);
    }
    Header.m_nOffsetParamsLocal = gEnv->pCryPak->FTell(fpDst);
    gEnv->pCryPak->FSeek(fpDst, 0, SEEK_SET);
    if (CParserBin::m_bEndians)
    {
      hdTemp = Header;
      SwapEndian(hdTemp, eBigEndian);
      pHD = &hdTemp;
    }
    gEnv->pCryPak->FWrite((void *)pHD, sizeof(Header), 1, fpDst);
    gEnv->pCryPak->FClose(fpDst);
  }
  else
  {
    iLog->LogWarning("CShaderManBin::SaveBinShader: Cannot write shader to file '%s'.", nameFile);
    pBin->m_bReadOnly = true;
  }

  SAFE_DELETE_ARRAY(pBuf);

  return pBin;
}

//=========================================================================================================================================

static void sParseCSV(string& sFlt, std::vector<string>& Filters)
{
  const char *cFlt = sFlt.c_str();
  char Flt[64];
  int nFlt = 0;
  while(true)
  {
    char c = *cFlt++;
    if (!c)
      break;
    if (sSkipChars[(unsigned char)c])
    {
      if (nFlt)
      {
        Flt[nFlt] = 0;
        Filters.push_back(string(Flt));
        nFlt = 0;
      }
      continue;
    }
    Flt[nFlt++] = c;
  }
  if (nFlt)
  {
    Flt[nFlt] = 0;
    Filters.push_back(string(Flt));
  }
}

//===========================================================================================================================

struct FXParamsSortByName
{
  bool operator () (const SFXParam& left, const SFXParam& right)const
  {
    return left.m_dwName[0] < right.m_dwName[0];
  }
  bool operator () (const uint32 left, const SFXParam& right)const
  {
    return left < right.m_dwName[0];
  }
  bool operator () (const SFXParam& left, uint32 right)const
  {
    return left.m_dwName[0] < right;
  }
};
struct FXSamplersSortByName
{
  bool operator () (const STexSamplerFX& left, const STexSamplerFX& right)const
  {
    return left.m_szName < right.m_szName;
  }
  bool operator () (const string left, const STexSamplerFX& right)const
  {
    return left < right.m_szName;
  }
  bool operator () (const STexSamplerFX& left, string right)const
  {
    return left.m_szName < right;
  }
};

int CShaderManBin::mfSizeFXParams(uint32& nCount)
{
  nCount = m_ShaderFXParams.size();
  int nSize = sizeOfMap(m_ShaderFXParams);
  return nSize;
}

void CShaderManBin::mfReleaseFXParams()
{
  m_ShaderFXParams.clear();
}

SShaderFXParams& CShaderManBin::mfGetFXParams(CShader *pSH)
{
  CCryNameTSCRC s = pSH->GetNameCRC();
  ShaderFXParamsItor it = m_ShaderFXParams.find(s);
  if (it != m_ShaderFXParams.end())
    return it->second;
  SShaderFXParams pr;
	std::pair<ShaderFXParams::iterator, bool> insertLocation =
		m_ShaderFXParams.insert(std::pair<CCryNameTSCRC, SShaderFXParams>(s, pr));
	assert(insertLocation.second);
  return insertLocation.first->second;
}

SFXParam *CShaderManBin::mfAddFXParam(SShaderFXParams& FXP, const SFXParam *pParam)
{
  FXParamsIt it = std::lower_bound(FXP.m_FXParams.begin(), FXP.m_FXParams.end(), pParam->m_dwName[0], FXParamsSortByName());
  if (it != FXP.m_FXParams.end() && pParam->m_dwName[0] == (*it).m_dwName[0])
  {
    SFXParam& pr = *it;
    pr.m_nFlags = pParam->m_nFlags;
#if !defined (XENON) && !defined(PS3)
    int n = 6;


#endif
    SFXParam& p = *it;
    for (int i=0; i<n; i++)
    {
      if(p.m_nRegister[i] == 10000)
        p.m_nRegister[i] = pParam->m_nRegister[i]; 
    }
    //assert(p == *pParam);
    return &(*it);
  }
  FXP.m_FXParams.insert(it, *pParam);
  it = std::lower_bound(FXP.m_FXParams.begin(), FXP.m_FXParams.end(), pParam->m_dwName[0], FXParamsSortByName());
  SFXParam *pFX = &(*it);
  if (pFX->m_Assign.empty() && pFX->m_Values.c_str()[0] == '(')
    pFX->m_nCB = CB_PER_MATERIAL;
  FXP.m_nFlags |= FXP_PARAMS_DIRTY;

  return pFX;
}
SFXParam *CShaderManBin::mfAddFXParam(CShader *pSH, const SFXParam *pParam)
{
  if (!pParam)
    return NULL;

  SShaderFXParams& FXP = mfGetFXParams(pSH);
  return mfAddFXParam(FXP, pParam);
}
void CShaderManBin::mfAddFXSampler(CShader *pSH, const STexSamplerFX *pSamp)
{
  if (!pSamp)
    return;

  SShaderFXParams& FXP = mfGetFXParams(pSH);

  FXSamplersIt it = std::lower_bound(FXP.m_FXSamplers.begin(), FXP.m_FXSamplers.end(), pSamp->m_szName, FXSamplersSortByName());
  if (it != FXP.m_FXSamplers.end() && pSamp->m_szName == (*it).m_szName)
  {
    assert(*it == *pSamp);
    return;
  }
  FXP.m_FXSamplers.insert(it, *pSamp);
  FXP.m_nFlags |= FXP_SAMPLERS_DIRTY;
}

void CShaderManBin::mfGeneratePublicFXParams(CShader *pSH, CParserBin& Parser)
{
  SShaderFXParams& FXP = mfGetFXParams(pSH);
  if (!(FXP.m_nFlags & FXP_PARAMS_DIRTY))
    return;
  FXP.m_nFlags &= ~FXP_PARAMS_DIRTY;

  uint32 i;
  // Generate public parameters
  for (i=0; i<FXP.m_FXParams.size(); i++)
  {
    SFXParam *pr = &FXP.m_FXParams[i];
    uint32 nFlags = pr->GetParamFlags();
    if (nFlags & PF_AUTOMERGED)
      continue;
    if (nFlags & PF_TWEAKABLE_MASK)
    {
      const char *szName = Parser.GetString(pr->m_dwName[0]);
      // Avoid duplicating of public parameters
      int32 j;
      for (j=0; j<FXP.m_PublicParams.size(); j++)
      {
        SShaderParam *p = &FXP.m_PublicParams[j];
        if (!stricmp(p->m_Name, szName))
          break;
      }
      if (j == FXP.m_PublicParams.size())
      {
        SShaderParam sp;
        strncpy(sp.m_Name, szName, 32);
        EParamType eType;
        string szWidget = pr->GetValueForName("UIWidget", eType);
        const char *szVal = pr->m_Values.c_str();
        if (szWidget == "color")
        {
          sp.m_Type = eType_FCOLOR;
          if (szVal[0] == '{')
            szVal++;
          int n = sscanf(szVal, "%f, %f, %f, %f", &sp.m_Value.m_Color[0], &sp.m_Value.m_Color[1], &sp.m_Value.m_Color[2], &sp.m_Value.m_Color[3]);
          assert(n == 4);
        }
        else
        {
          sp.m_Type = eType_FLOAT;
          sp.m_Value.m_Float = (float)atof(szVal);
        }

        bool bAdd = true;
        if (!pr->m_Annotations.empty() && gRenDev->IsEditorMode())
        {
          //EParamType eType;
          string sFlt = pr->GetValueForName("Filter", eType);
          bool bUseScript = true;
          if (!sFlt.empty())
          {
            std::vector<string> Filters;
            sParseCSV(sFlt, Filters);
            string strShader = Parser.m_pCurShader->GetName();
            uint32 h;
            for (h=0; h<Filters.size(); h++)
            {
              if (!strnicmp(Filters[h].c_str(), strShader.c_str(), Filters[h].size()))
                break;
            }
            if (h == Filters.size())
            {
              bUseScript = false;
              bAdd = false;
            }
          }

          if (bUseScript)
          {
            sp.m_Script = pr->m_Annotations.c_str();
          }
        }
        
        if ( bAdd )
        {
          FXP.m_PublicParams.push_back(sp);
        }
      }
    }
  }
}

SParamCacheInfo *CShaderManBin::GetParamInfo(SShaderBin *pBin, uint32 dwName, uint64 nMaskGenFX)
{
  const int n = pBin->m_ParamsCache.size();
  for (int i=0; i<n; i++)
  {
    SParamCacheInfo *pInf = &pBin->m_ParamsCache[i];
    if (pInf->m_dwName == dwName && pInf->m_nMaskGenFX == nMaskGenFX)
    {
      pBin->m_nCurParamsID = i;
      return pInf;
    }
  }
  pBin->m_nCurParamsID = -1;
  return NULL;
}

bool CShaderManBin::SaveBinShaderLocalInfo(SShaderBin *pBin, uint32 dwName, uint64 nMaskGenFX, TArray<int32>& Funcs, std::vector<SFXParam>& Params)
{
  if (GetParamInfo(pBin, dwName, nMaskGenFX))
    return true;
  //return false;
  if (pBin->IsReadOnly())
    return false;
  TArray<int32> EParams;
  TArray<int32> EFuncs;
  for (uint32 i=0; i<Params.size(); i++)
  {
    SFXParam& pr = Params[i];
    assert(pr.m_dwName.size());
    if (pr.m_dwName.size())
      EParams.push_back(pr.m_dwName[0]);
  }
  pBin->m_nCurParamsID = pBin->m_ParamsCache.size();
	pBin->m_ParamsCache.push_back(SParamCacheInfo());
  SParamCacheInfo& pr = pBin->m_ParamsCache.back();
  pr.m_nMaskGenFX = nMaskGenFX;
  pr.m_dwName = dwName;
  pr.m_AffectedFuncs.assign(Funcs.begin(), Funcs.end());
  pr.m_AffectedParams.assign(EParams.begin(), EParams.end());
  FILE *fpBin = gEnv->pCryPak->FOpen(pBin->m_szName, "r+b");
  assert(fpBin);
  if (!fpBin)
    return false;
  gEnv->pCryPak->FSeek(fpBin, 0, SEEK_END);
  int nSeek = gEnv->pCryPak->FTell(fpBin);
  assert(nSeek > 0);
  if (nSeek <= 0)
    return false;
  SShaderBinParamsHeader sd;
  int32 *pFuncs = &Funcs[0];
  int32 *pParams = EParams.size() ? &EParams[0] : NULL;
  sd.nMask = nMaskGenFX;
  sd.nName = dwName;
  sd.nFuncs = Funcs.size();
  sd.nParams = EParams.size();
  if (CParserBin::m_bEndians)
  {
    SwapEndian(sd, eBigEndian);
    EFuncs = Funcs;
    if (EParams.size())
      SwapEndian(&EParams[0], EParams.size(), eBigEndian);
    SwapEndian(&EFuncs[0], EFuncs.size(), eBigEndian);
    pFuncs = &EFuncs[0];
  }
  gEnv->pCryPak->FWrite(&sd, sizeof(sd), 1, fpBin);
  if (EParams.size())
    gEnv->pCryPak->FWrite(pParams, EParams.size(), sizeof(int32), fpBin);
  gEnv->pCryPak->FWrite(pFuncs, Funcs.size(), sizeof(int32), fpBin);
  gEnv->pCryPak->FClose(fpBin);

  return true;
}

SShaderBin *CShaderManBin::LoadBinShader(FILE *fpBin, const char *szName, const char *szNameBin, bool bReadParams)
{
  LOADING_TIME_PROFILE_SECTION(iSystem);

  gEnv->pCryPak->FSeek(fpBin, 0, SEEK_SET);
  SShaderBinHeader Header;
  size_t sizeRead = gEnv->pCryPak->FReadRaw(&Header, 1, sizeof(SShaderBinHeader), fpBin);
	if( sizeRead != sizeof(SShaderBinHeader) )
	{
		CryWarning( VALIDATOR_MODULE_RENDERER, VALIDATOR_ERROR, "Failed to read header for %s in CShaderManBin::LoadBinShader. Expected %d, got %d", szName, (int32)sizeof(SShaderBinHeader), (int32)sizeRead );
		return NULL;
	}

  if (CParserBin::m_bEndians)
    SwapEndian(Header, eBigEndian);
  float fVersion = (float)FX_CACHE_VER;
  uint16 MinorVer = (uint16)(((float)fVersion - (float)(int)fVersion)*10.1f);
  uint16 MajorVer = (uint16)fVersion;
  bool bCheckValid = !CRenderer::CV_r_shadersnocompile;
  if (bCheckValid && (Header.m_VersionLow != MinorVer || Header.m_VersionHigh != MajorVer || Header.m_Magic != FOURCC_SHADERBIN))
    return NULL;
  if (Header.m_VersionHigh > 10)
    return NULL;
  SShaderBin *pBin = new SShaderBin;

  pBin->m_SourceCRC32 = Header.m_nSourceCRC32;
  pBin->m_nOffsetLocalInfo = Header.m_nOffsetParamsLocal;

  uint32 CRC32 = Header.m_CRC32;
  pBin->m_CRC32 = CRC32;
  pBin->m_Tokens.resize(Header.m_nTokens);
  sizeRead = gEnv->pCryPak->FReadRaw(&pBin->m_Tokens[0], sizeof(uint32), Header.m_nTokens, fpBin);
	if( sizeRead != Header.m_nTokens )
	{
		CryWarning(VALIDATOR_MODULE_RENDERER, VALIDATOR_ERROR, "Failed to read Tokens for %s in CShaderManBin::LoadBinShader. Expected %d, got %d", szName, Header.m_nTokens, (int32)sizeRead);
		return NULL;
	}
  if (CParserBin::m_bEndians)
    SwapEndian(&pBin->m_Tokens[0], Header.m_nTokens, eBigEndian);

  //pBin->CryptData();
  int nSizeTable = Header.m_nOffsetParamsLocal - Header.m_nOffsetStringTable;
  if (nSizeTable < 0)
    return NULL;
  char *bufTable = new char[nSizeTable];
  char *bufT = bufTable;
  sizeRead = gEnv->pCryPak->FReadRaw(bufTable, 1, nSizeTable, fpBin);
	if( sizeRead != nSizeTable )
	{
		CryWarning(VALIDATOR_MODULE_RENDERER, VALIDATOR_ERROR, "Failed to read bufTable for %s in CShaderManBin::LoadBinShader. Expected %d, got %d", szName, nSizeTable, (int32)sizeRead);
		return NULL;
	}
  char *bufEnd = &bufTable[nSizeTable];

	// First pass to count the tokens
	uint32 nTokens(0);
	while (bufTable < bufEnd)
	{
		STokenD TD;
		TD.Token = *(uint32 *)bufTable;
		int nIncr = 4 + strlen(&bufTable[4]) + 1;
		bufTable += nIncr;
		++nTokens;
	}

	pBin->m_TokenTable.reserve(nTokens);
	bufTable = bufT;
  while (bufTable < bufEnd)
  {
    STokenD TD;
		TD.Token = *(uint32 *)bufTable;
		if (CParserBin::m_bEndians)
			SwapEndian(TD.Token, eBigEndian);
    FXShaderTokenItor itor = std::lower_bound(pBin->m_TokenTable.begin(), pBin->m_TokenTable.end(), TD.Token, SortByToken());
    assert (itor == pBin->m_TokenTable.end() || (*itor).Token != TD.Token);
    TD.SToken = &bufTable[4];
    pBin->m_TokenTable.insert(itor, TD);
    int nIncr = 4 + strlen(&bufTable[4]) + 1;
    bufTable += nIncr;
  }
  SAFE_DELETE_ARRAY(bufT);

  //if (CRenderer::CV_r_shadersnocompile)
  //  bReadParams = false;
  if (bReadParams)
  {
    int nSeek = pBin->m_nOffsetLocalInfo;
    gEnv->pCryPak->FSeek(fpBin, nSeek, SEEK_SET);
    while(true)
    {
      SShaderBinParamsHeader sd;
      int nSize = gEnv->pCryPak->FReadRaw(&sd, 1, sizeof(sd), fpBin);
      if (nSize != sizeof(sd))
			{
				break;
			}
      if (CParserBin::m_bEndians)
        SwapEndian(sd, eBigEndian);
      SParamCacheInfo pr;
      int n = pBin->m_ParamsCache.size();
      pBin->m_ParamsCache.push_back(pr);
      SParamCacheInfo& prc = pBin->m_ParamsCache[n];
      prc.m_dwName = sd.nName;
      prc.m_nMaskGenFX = sd.nMask;
      prc.m_AffectedParams.resize(sd.nParams);
      prc.m_AffectedFuncs.resize(sd.nFuncs);

      if (sd.nParams)
      {
				nSize = gEnv->pCryPak->FReadRaw(&prc.m_AffectedParams[0], sizeof(int32), sd.nParams, fpBin);
				if (nSize != sd.nParams)
				{
					CryWarning(VALIDATOR_MODULE_RENDERER, VALIDATOR_ERROR, "Failed to read m_AffectedParams for %s in CShaderManBin::LoadBinShader. Expected %d, got %d", szName, sd.nParams, (int32)sizeRead);
					return NULL;
				}
        if (CParserBin::m_bEndians)
          SwapEndian(&prc.m_AffectedParams[0], sd.nParams, eBigEndian);
      }

      assert(sd.nFuncs > 0);
      nSize = gEnv->pCryPak->FReadRaw(&prc.m_AffectedFuncs[0], sizeof(int32), sd.nFuncs, fpBin);
			if (nSize != sd.nFuncs)
			{
				CryWarning(VALIDATOR_MODULE_RENDERER, VALIDATOR_ERROR, "Failed to read nFuncs for %s in CShaderManBin::LoadBinShader. Expected %d, got %d", szName, sd.nParams, (int32)sizeRead);
				return NULL;
			}
      if (CParserBin::m_bEndians)
        SwapEndian(&prc.m_AffectedFuncs[0], sd.nFuncs, eBigEndian);

      nSeek += (sd.nFuncs)*sizeof(int32) + sizeof(sd);
    }
  }

  char nameLwr[256];
  strcpy_s(nameLwr, szName);
  strlwr(nameLwr);
  pBin->SetName(szNameBin);
  pBin->m_dwName = CParserBin::GetCRC32(nameLwr);

  return pBin;
}

SShaderBin *CShaderManBin::SearchInCache(const char *szName, bool bInclude)
{
  char nameFile[256], nameLwr[256];
  strcpy_s(nameLwr, szName);
  strlwr(nameLwr);
  sprintf(nameFile, "%s.%s", nameLwr, bInclude ? "cfi" : "cfx");
  uint32 dwName = CParserBin::GetCRC32(nameFile);

  SShaderBin *pSB;
  for (pSB=SShaderBin::m_Root.m_Prev; pSB!=&SShaderBin::m_Root; pSB=pSB->m_Prev)
  {
    if (pSB->m_dwName == dwName)
    {
      pSB->Unlink();
      pSB->Link(&SShaderBin::m_Root);
      return pSB;
    }
  }
   return NULL;
}

bool CShaderManBin::AddToCache(SShaderBin *pSB, bool bInclude)
{
	if (!CRenderer::CV_r_shadersediting)
	{
		if (SShaderBin::m_nCache >= SShaderBin::m_nMaxFXBinCache)
		{
			SShaderBin *pS;
			for (pS=SShaderBin::m_Root.m_Prev; pS!=&SShaderBin::m_Root; pS=pS->m_Prev)
			{
				if (!pS->m_bLocked)
				{
					DeleteFromCache(pS);
					break;
				}
			}
		}
		assert(SShaderBin::m_nCache < SShaderBin::m_nMaxFXBinCache);
	}

  pSB->m_bInclude = bInclude;
  pSB->Link(&SShaderBin::m_Root);
  SShaderBin::m_nCache++;

  return true;
}

bool CShaderManBin::DeleteFromCache(SShaderBin *pSB)
{
  assert(pSB != &SShaderBin::m_Root);
  pSB->Unlink();
  SAFE_DELETE(pSB);
  SShaderBin::m_nCache--;

  return true;
}

void CShaderManBin::InvalidateCache(bool bIncludesOnly)
{
  SShaderBin *pSB, *Next;
  for (pSB=SShaderBin::m_Root.m_Next; pSB!=&SShaderBin::m_Root; pSB=Next)
  {
    Next = pSB->m_Next;
    if (bIncludesOnly && !pSB->m_bInclude)
      continue;
    DeleteFromCache(pSB);
  }
  SShaderBin::m_nMaxFXBinCache = MAX_FXBIN_CACHE;
	m_bBinaryShadersLoaded = false;
	stl::free_container(s_tempFXParams);

	g_shaderBucketAllocator.cleanup();
}

#define SEC5_FILETIME 10*1000*1000*5


SShaderBin *CShaderManBin::GetBinShader(const char *szName, bool bInclude, uint32 nRefCRC, bool *pbChanged)
{
	//static float sfTotalTime = 0.0f;

	//for PS3 loading time matters, by using a special flag the sources do not matter and no modification time check is performed
  if (pbChanged)
  {
    if (gRenDev->IsEditorMode())
      *pbChanged = false;
		/*
    else
      *pbChanged = true;
			*/
  }

	//float fTime0 = iTimer->GetAsyncCurTime();

  SShaderBin *pSHB = SearchInCache(szName, bInclude);
  if (pSHB)
    return pSHB;
  SShaderBinHeader Header[2];
	memset(&Header, 0, 2 * sizeof(SShaderBinHeader));
  char nameFile[256], nameBin[256];
	FILE *fpSrc = NULL;
	uint32 nSourceCRC32 = 0;
  sprintf(nameFile, "%sCryFX/%s.%s", gRenDev->m_cEF.m_ShadersPath, szName, bInclude ? "cfi" : "cfx");
#if !defined(_RELEASE) && !defined(CRYTEK_SDK_EVALUATION) && !defined(IS_CRYDEV)
	{
		fpSrc = gEnv->pCryPak->FOpen(nameFile, "rb");
		nSourceCRC32 = fpSrc ? gEnv->pCryPak->ComputeCRC(nameFile) : 0;
	}
#endif
  //char szPath[1024];
  //getcwd(szPath, 1024);
  sprintf(nameBin, "%s%s.%s", m_pCEF->m_ShadersCache, szName, bInclude ? "cfib" : "cfxb");
  FILE *fpDst = NULL;
  int i=0, n = 2;

	// don't load from the shadercache.pak when in editing mode
	if (CRenderer::CV_r_shadersediting)
		i = 1;

  string szDst = m_pCEF->m_szUserPath + nameBin;
  byte bValid = 0;
  float fVersion = (float)FX_CACHE_VER;
  for (; i<n; i++)
  {
    if (fpDst)
      gEnv->pCryPak->FClose(fpDst);
    if (!i)
		{
			if (n == 2)
			{
				char nameLwr[256];
				sprintf(nameLwr, "%s.%s", szName, bInclude ? "cfi" : "cfx");
				strlwr(nameLwr);
				uint32 dwName = CParserBin::GetCRC32(nameLwr);
				FXShaderBinValidCRCItor itor = m_BinValidCRCs.find(dwName);
				if (itor != m_BinValidCRCs.end())
				{
					assert(itor->second == false);
					continue;
				}
			}
      fpDst = gEnv->pCryPak->FOpen(nameBin, "rb");
		}
    else
      fpDst = gEnv->pCryPak->FOpen(szDst.c_str(), "rb");
    if (!fpDst)
      continue;
    else
    {
			//if changing these lines, please also do below where dedicated PS3 stuff is
			gEnv->pCryPak->FReadRaw(&Header[i], 1, sizeof(SShaderBinHeader), fpDst);
			if (CParserBin::m_bEndians)
				SwapEndian(Header[i], eBigEndian);

#if !defined(_RELEASE) && !defined(CRYTEK_SDK_EVALUATION) && !defined(IS_CRYDEV)
			// check source crc changes
			if (nSourceCRC32 && nSourceCRC32 != Header[i].m_nSourceCRC32) {
				bValid |= 1<<i;
			} else 
#endif
			{			
				uint16 MinorVer = (uint16)(((float)fVersion - (float)(int)fVersion)*10.1f);
				uint16 MajorVer = (uint16)fVersion;
				if (Header[i].m_VersionLow != MinorVer || Header[i].m_VersionHigh != MajorVer || Header[i].m_Magic != FOURCC_SHADERBIN)
					bValid |= 4<<i;
				else
					if (nRefCRC && Header[i].m_CRC32 != nRefCRC)
						bValid |= 0x10<<i;
			}
    }
    if (!(bValid & (0x15<<i)))
      break;
  }
  if (i==n)
  {
#if !defined(_RELEASE) && !defined(CRYTEK_SDK_EVALUATION) && !defined(IS_CRYDEV) && !defined(CONSOLE_CONST_CVAR_MODE)
    {
			char acTemp[512];
      if (bValid & 1)
			  sprintf_s(acTemp, 512, "WARNING: Bin FXShader '%s' source crc mismatch", nameBin);
      if (bValid & 4)
        sprintf_s(acTemp, 512, "WARNING: Bin FXShader '%s' version mismatch (Cache: %d.%d, Expected: %.1f)", nameBin, Header[0].m_VersionHigh, Header[0].m_VersionLow, fVersion);
      if (bValid & 0x10)
        sprintf_s(acTemp, 512, "WARNING: Bin FXShader '%s' CRC mismatch", nameBin);

      if (bValid & 2)
        sprintf_s(acTemp, 512, "WARNING: Bin FXShader USER '%s' source crc mismatch", nameBin);
      if (bValid & 8)
        sprintf_s(acTemp, 512, "WARNING: Bin FXShader USER '%s' version mismatch (Cache: %d.%d, Expected: %.1f)", nameBin, Header[1].m_VersionHigh, Header[1].m_VersionLow, fVersion);
      if (bValid & 0x20)
        sprintf_s(acTemp, 512, "WARNING: Bin FXShader USER '%s' CRC mismatch", nameBin);

			if (bValid)
				LogWarning(acTemp);

      if (fpDst)
      {
        gEnv->pCryPak->FClose(fpDst);
        fpDst = NULL;
      }

      if (fpSrc)
      {
				// enable shader compilation again, and show big error message
				if (CRenderer::CV_r_shadersnocompile)
				{
					if (CRenderer::CV_r_shaderscompileautoactivate)
					{
						CRenderer::CV_r_shadersnocompile = 0;
						CRenderer::CV_r_shadersasyncactivation = 0;

						gEnv->pLog->LogError("ERROR LOADING BIN SHADER - REACTIVATING SHADER COMPILATION !");
					} else
					{
						static bool bShowMessageBox = true;

						if (bShowMessageBox)
						{
							IPlatformOS::EMsgBoxResult result;

							IPlatformOS* pOS = gEnv->pSystem->GetPlatformOS();
							if (pOS)
							{
								result = pOS->DebugMessageBox( acTemp, "Invalid ShaderCache" );

								if (result == IPlatformOS::eMsgBox_Cancel)
								{
									DebugBreak();
								}
								else
								{
									bShowMessageBox = false;
									Sleep(33);
								}
							}
						}						
					}
				}

				if (!CRenderer::CV_r_shadersnocompile)
				{
					pSHB = SaveBinShader(nSourceCRC32, szName, bInclude, fpSrc);
					assert(!pSHB->m_Next);
					if (pbChanged)
						*pbChanged = true;

					// remove the entries in the looupdata, to be sure that level and global caches have also become invalid for these shaders!
					gRenDev->m_cEF.m_ResLookupDataMan[CACHE_READONLY].RemoveData(Header[0].m_CRC32);
					gRenDev->m_cEF.m_ResLookupDataMan[CACHE_USER].RemoveData(Header[1].m_CRC32);

					// has the shader been successfully written to the dest address
					fpDst = gEnv->pCryPak->FOpen(szDst.c_str(), "rb");
					if (fpDst)
					{
						SAFE_DELETE(pSHB);
						i = 1;
					}
				}
      }
    }
#endif
  }
	if (fpSrc)
		gEnv->pCryPak->FClose(fpSrc);
	fpSrc = NULL;

  if (CRenderer::CV_r_shadersnocompile)
  {
    if (pSHB == 0 && !fpDst)
	  {
		  //do only perform the necessary stuff
		  fpDst = gEnv->pCryPak->FOpen(nameBin, "rb");
	  }
  }
  if (pSHB == 0 && fpDst)
  {
    sprintf(nameFile, "%s.%s", szName, bInclude ? "cfi" : "cfx");
    pSHB = LoadBinShader(fpDst, nameFile, i==0 ? nameBin : szDst.c_str(), !bInclude);
    gEnv->pCryPak->FClose(fpDst);
    assert(pSHB);    
  }

	if (pSHB)
	{
		if (i == 0)
			pSHB->m_bReadOnly = true;
		else
			pSHB->m_bReadOnly = false;

		AddToCache(pSHB, bInclude);
		if (!bInclude)
		{
			char nm[128];
			nm[0] = '$';
			strcpy(&nm[1], szName);
			CCryNameTSCRC NM = CParserBin::GetPlatformSpecName(nm);
			FXShaderBinPathItor it = m_BinPaths.find(NM);
			if (it == m_BinPaths.end())
				m_BinPaths.insert(FXShaderBinPath::value_type(NM, i==0 ? string(nameBin) : szDst));
			else
				it->second = (i==0) ? string(nameBin) : szDst;
		}
	} else {
    if (fpDst)
      Warning("Error: Failed to get binary shader '%s'", nameFile);
    else
		{
			sprintf(nameFile, "%s.%s", szName, bInclude ? "cfi" : "cfx");
			const char* matName = 0;
			if (m_pCEF && m_pCEF->m_pCurInputResources)
				matName = m_pCEF->m_pCurInputResources->m_szMaterialName;
			Warning("Error: Shader \"%s\" doesn't exist (used in material \"%s\")", nameFile, matName != 0 ? matName : "$unknown$");
		}
  }

	/*
	sfTotalTime += iTimer->GetAsyncCurTime() - fTime0;

	{
		char acTmp[1024];
		sprintf(acTmp, "Parsing of bin took: %f \n", sfTotalTime);
		OutputDebugString(acTmp);
	}
	*/

  return pSHB;
}

void CShaderManBin::AddGenMacroses(SShaderGen *shG, CParserBin& Parser, uint64 nMaskGen)
{
  if (!nMaskGen || !shG)
    return;

  uint32 dwMacro = eT_1;
  for (uint32 i=0; i<shG->m_BitMask.Num(); i++)
  {
    if (shG->m_BitMask[i]->m_Mask & nMaskGen)
    {
      Parser.AddMacro(shG->m_BitMask[i]->m_dwToken, &dwMacro, 1, shG->m_BitMask[i]->m_Mask, Parser.m_Macros[1]);
    }
  }
}

bool CShaderManBin::ParseBinFX_Global_Annotations(CParserBin& Parser, SParserFrame& Frame, bool *bPublic, CCryNameR techStart[2])
{
  bool bRes = true;

  SParserFrame OldFrame = Parser.BeginFrame(Frame);

  FX_BEGIN_TOKENS
    FX_TOKEN(ShaderType)
    FX_TOKEN(ShaderDrawType)
    FX_TOKEN(PreprType)
    FX_TOKEN(Public)
    FX_TOKEN(NoPreview)
    FX_TOKEN(LocalConstants)
    FX_TOKEN(Cull)
    FX_TOKEN(SupportsAttrInstancing)
    FX_TOKEN(SupportsConstInstancing)
    FX_TOKEN(SupportsDeferredShading)
		FX_TOKEN(SupportsFullDeferredShading)
    FX_TOKEN(Decal)
    FX_TOKEN(DecalNoDepthOffset)
    FX_TOKEN(DeferredBackLighting)
    FX_TOKEN(HWTessellation)
    FX_TOKEN(VertexColors)
    FX_TOKEN(NoChunkMerging)
    FX_TOKEN(ForceTransPass)
    FX_TOKEN(AfterHDRPostProcess)
    FX_TOKEN(AfterPostProcess)
    FX_TOKEN(ForceZpass)
    FX_TOKEN(ForceWaterPass)
    FX_TOKEN(ForceDrawLast)
    FX_TOKEN(ForceDrawFirst)
    FX_TOKEN(Hair)
		FX_TOKEN(SkinPass)
    FX_TOKEN(ForceGeneralPass)
    FX_TOKEN(ForceDrawAfterWater)
    FX_TOKEN(SupportsSubSurfaceScattering)
    FX_TOKEN(SupportsReplaceBasePass)
    FX_TOKEN(SingleLightPass)
    FX_TOKEN(Refractive)
    FX_TOKEN(ForceRefractionUpdate)
    FX_TOKEN(WaterParticle)
    FX_TOKEN(VT_DetailBending)
    FX_TOKEN(VT_DetailBendingGrass)
    FX_TOKEN(VT_TerrainAdapt)
    FX_TOKEN(VT_WindBending)
		FX_TOKEN(AlphaBlendShadows)
  FX_END_TOKENS

  int nIndex;
  CShader *ef = Parser.m_pCurShader;

  while (Parser.ParseObject(sCommands, nIndex))
  {
    EToken eT = Parser.GetToken();
    switch (eT)
    {
      case eT_Public:
        if (bPublic)
          *bPublic = true;
        break;

      case eT_NoPreview:
        if (!ef)
          break;
        ef->m_Flags |= EF_NOPREVIEW;
        break;

      case eT_Decal:
        if (!ef)
          break;
        ef->m_Flags |= EF_DECAL;
        ef->m_nMDV |= MDV_DEPTH_OFFSET;
        break;

      case eT_DecalNoDepthOffset:
        if (!ef)
          break;
        ef->m_Flags |= EF_DECAL;
        break;


      case eT_LocalConstants:
        if (!ef)
          break;
        ef->m_Flags |= EF_LOCALCONSTANTS;
        break;

      case eT_VT_DetailBending:
        if (!ef)
          break;
        ef->m_nMDV |= MDV_DET_BENDING;
        break;
      case eT_VT_DetailBendingGrass:
        if (!ef)
          break;
        ef->m_nMDV |= MDV_DET_BENDING | MDV_DET_BENDING_GRASS;
        break;
      case eT_VT_WindBending:
        if (!ef)
          break;
        ef->m_nMDV |= MDV_WIND;
        break;
      case eT_VT_TerrainAdapt:
        if (!ef)
          break;
        ef->m_nMDV |= MDV_TERRAIN_ADAPT;
        break;

      case eT_NoChunkMerging:
        if (!ef)
          break;
        ef->m_Flags |= EF_NOCHUNKMERGING;
        break;

      case eT_SupportsAttrInstancing:
        if (!ef)
          break;
        if (gRenDev->m_bDeviceSupportsInstancing)
          ef->m_Flags |= EF_SUPPORTSINSTANCING_ATTR;
        break;
      case eT_SupportsConstInstancing:
        if (!ef)
          break;
        if (gRenDev->m_bDeviceSupportsInstancing)
          ef->m_Flags |= EF_SUPPORTSINSTANCING_CONST;
        break;
  
      case eT_SupportsDeferredShading:
        if (!ef)
          break;
          ef->m_Flags |= EF_SUPPORTSDEFERREDSHADING_MIXED;
        break;
				
			case eT_SupportsFullDeferredShading:
				if (!ef)
					break;
				ef->m_Flags |= EF_SUPPORTSDEFERREDSHADING_FULL;
				break;

      case eT_ForceTransPass:        
        if (!ef)
          break;
        ef->m_Flags2 |= EF2_FORCE_TRANSPASS;
        break;

      case eT_AfterHDRPostProcess: 
        if (!ef)
          break;
        ef->m_Flags2 |= EF2_AFTERHDRPOSTPROCESS;
        break;

	  case eT_AfterPostProcess: 
		  if (!ef)
			  break;
		  ef->m_Flags2 |= EF2_AFTERPOSTPROCESS;
		  break;

      case eT_ForceZpass:        
        if (!ef)
          break;
        ef->m_Flags2 |= EF2_FORCE_ZPASS;
        break;

      case eT_ForceWaterPass:        
        if (!ef)
          break;
        ef->m_Flags2 |= EF2_FORCE_WATERPASS;
        break;

      case eT_ForceDrawLast:        
        if (!ef)
          break;
        ef->m_Flags2 |= EF2_FORCE_DRAWLAST;
        break;
      case eT_ForceDrawFirst: 
        if (!ef)
          break;
        ef->m_Flags2 |= EF2_FORCE_DRAWFIRST;
        break;
        
      case eT_Hair:        
        if (!ef)
          break;
        ef->m_Flags2 |= EF2_HAIR;
        break;

      case eT_ForceGeneralPass: 
        if (!ef)
          break;
        ef->m_Flags2 |= EF2_FORCE_GENERALPASS;
        break;

      case eT_ForceDrawAfterWater:
        if (!ef)
          break;
        ef->m_Flags2 |= EF2_FORCE_DRAWAFTERWATER;
        break;
      case eT_SupportsSubSurfaceScattering:
        if (!ef)
          break;
        ef->m_Flags2 |= EF2_DEPTHMAP_SUBSURFSCATTER;
        break;
      case eT_SupportsReplaceBasePass:
        if (!ef)
          break;
        ef->m_Flags2 |= EF2_SUPPORTS_REPLACEBASEPASS;
        break;
      case eT_SingleLightPass:
        if (!ef)
          break;
        ef->m_Flags2 |= EF2_SINGLELIGHTPASS;      
        break;
      case eT_WaterParticle:
        if (!ef)
          break;
        ef->m_Flags |= EF_WATERPARTICLE;
        break;
      case eT_Refractive:
        if (!ef)
          break;
        ef->m_Flags |= EF_REFRACTIVE;
        break;
	  case eT_ForceRefractionUpdate:
		  if (!ef)
			  break;
		  ef->m_Flags |= EF_FORCEREFRACTIONUPDATE;
		  break;

      case eT_DeferredBackLighting:
        if (!ef)
          break;
        ef->m_Flags2 |= EF2_DEFERBACKLIGHTING;
        break;

      case eT_HWTessellation:
        if (!ef)
          break;
        ef->m_Flags2 |= EF2_HW_TESSELLATION;
        break;

      case eT_AlphaBlendShadows:
				if (!ef)
					break;
				ef->m_Flags2 |= EF2_ALPHABLENDSHADOWS;
				break;

			case eT_SkinPass:
				if (!ef)
					break;
				ef->m_Flags2 |= EF2_SKINPASS;
				break;

      case eT_VertexColors:
        if (!ef)
          break;
        ef->m_Flags2 |= EF2_VERTEXCOLORS;
        break;

      case eT_ShaderDrawType:
        {
          if (!ef)
            break;
          eT = Parser.GetToken(Parser.m_Data);
          if (eT == eT_Light)
            ef->m_eSHDType = eSHDT_Light;
          else
          if (eT == eT_Shadow)
            ef->m_eSHDType = eSHDT_Shadow;
          else
          if (eT == eT_Fur)
            ef->m_eSHDType = eSHDT_Fur;
          else
          if (eT == eT_General)
            ef->m_eSHDType = eSHDT_General;
          else
          if (eT == eT_Terrain)
            ef->m_eSHDType = eSHDT_Terrain;
          else
          if (eT == eT_Overlay)
            ef->m_eSHDType = eSHDT_Overlay;
          else
          if (eT == eT_NoDraw)
          {
            ef->m_eSHDType = eSHDT_NoDraw;
            ef->m_Flags |= EF_NODRAW;
          }
          else
          if (eT == eT_Custom)
            ef->m_eSHDType = eSHDT_CustomDraw;
          else
          if (eT == eT_Sky)
          {
            ef->m_eSHDType = eSHDT_Sky;
            ef->m_Flags |= EF_SKY;
          }
          else
          if (eT == eT_OceanShore)
            ef->m_eSHDType = eSHDT_OceanShore;
          else
          {
            Warning("Unknown shader draw type '%s'", Parser.GetString(eT));
          }
        }
        break;

      case eT_ShaderType:
        {
          if (!ef)
            break;
          eT = Parser.GetToken(Parser.m_Data);
          if (eT == eT_General)
            ef->m_eShaderType = eST_General;
          else
          if (eT == eT_Metal)
            ef->m_eShaderType = eST_Metal;
          else
          if (eT == eT_Ice)
            ef->m_eShaderType = eST_Ice;
          else
          if (eT == eT_Shadow)
            ef->m_eShaderType = eST_Shadow;
          else
          if (eT == eT_Water)
            ef->m_eShaderType = eST_Water;
          else
          if (eT == eT_FX)
            ef->m_eShaderType = eST_FX;
          else
          if (eT == eT_PostProcess)
            ef->m_eShaderType = eST_PostProcess;
          else
          if (eT == eT_HDR)
            ef->m_eShaderType = eST_HDR;
          else
          if (eT == eT_Sky)
            ef->m_eShaderType = eST_Sky;
          else
          if (eT == eT_Glass)
            ef->m_eShaderType = eST_Glass;
          else
          if (eT == eT_Vegetation)
            ef->m_eShaderType = eST_Vegetation;
          else
          if (eT == eT_Particle)
            ef->m_eShaderType = eST_Particle;
          else
          if (eT == eT_Terrain)
            ef->m_eShaderType = eST_Terrain;
          else
          if (eT == eT_Compute)
            ef->m_eShaderType = eST_Compute;
          else
          {
            Warning("Unknown shader type '%s'", Parser.GetString(eT));
            assert(0);
          }
        }
        break;

      case eT_PreprType:
        {
          if (!ef)
            break;
          eT = Parser.GetToken(Parser.m_Data);
          if (eT == eT_GenerateSprites)
            ef->m_Flags2 |= EF2_PREPR_GENSPRITES;
          else
          if (eT == eT_GenerateClouds)
            ef->m_Flags2 |= EF2_PREPR_GENCLOUDS;
          else
          if (eT == eT_ScanWater)
            ef->m_Flags2 |= EF2_PREPR_SCANWATER;
          else
          {
            Warning("Unknown preprocess type '%s'", Parser.GetString(eT));
            assert(0);
          }
        }
        break;

      case eT_Cull:
        {
          if (!ef)
            break;
          eT = Parser.GetToken(Parser.m_Data);
          if (eT == eT_None || eT == eT_NONE)
            ef->m_eCull = eCULL_None;
          else
          if (eT == eT_CCW || eT == eT_Back)
            ef->m_eCull = eCULL_Back;
          else
          if (eT == eT_CW || eT == eT_Front)
            ef->m_eCull = eCULL_Front;
          else
            assert(0);
        }
        break;

      default:
        assert(0);
    }
  }

  Parser.EndFrame(OldFrame);

  return bRes;
}

bool CShaderManBin::ParseBinFX_Global(CParserBin& Parser, SParserFrame& Frame, bool* bPublic, CCryNameR techStart[2])
{
  bool bRes = true;

  SParserFrame OldFrame = Parser.BeginFrame(Frame);

  FX_BEGIN_TOKENS
    FX_TOKEN(string)
  FX_END_TOKENS

  int nIndex;
  while (Parser.ParseObject(sCommands, nIndex))
  {
    EToken eT = Parser.GetToken();
    switch (eT)
    {
    case eT_string:
      {
        eT = Parser.GetToken(Parser.m_Name);
        assert(eT == eT_Script);
        bRes &= ParseBinFX_Global_Annotations(Parser, Parser.m_Data, bPublic, techStart);
      }
      break;

    default:
      assert(0);
    }
  }

  Parser.EndFrame(OldFrame);

  return bRes;
}

static int sGetTAddress(uint32 nToken)
{
  switch (nToken)
  {
    case eT_Clamp:
      return TADDR_CLAMP;
    case eT_Border:
      return TADDR_BORDER;
    case eT_Wrap:
      return TADDR_WRAP;
    case eT_Mirror:
      return TADDR_MIRROR;
    default:
      assert(0);
  }
  return -1;
}

void STexSamplerFX::PostLoad()
{
  SHRenderTarget *pRt = m_pTarget;
  if (!pRt)
    return;
  if (!strnicmp(m_szTexture.c_str(), "$RT_2D", 6))
  {
    if (pRt->m_nIDInPool >= 0)
    {
      if ((int)CTexture::s_CustomRT_2D.Num() <= pRt->m_nIDInPool)
        CTexture::s_CustomRT_2D.Expand(pRt->m_nIDInPool+1);
    }
    pRt->m_pTarget[0] = CTexture::s_ptexRT_2D;
  }
  else
  if (!strnicmp(m_szTexture.c_str(), "$RT_Cube", 8) || !strnicmp(m_szName.c_str(), "$RT_CM", 6))
  {
    if (pRt->m_nIDInPool >= 0)
    {
      if ((int)CTexture::s_CustomRT_CM.Num() <= pRt->m_nIDInPool)
        CTexture::s_CustomRT_CM.Expand(pRt->m_nIDInPool+1);
    }
    pRt->m_pTarget[0] = CTexture::s_ptexRT_CM;
  }
}

bool CShaderManBin::ParseBinFX_Sampler_Annotations_Script(CParserBin& Parser, SParserFrame& Frame, STexSamplerFX *pSampler)
{
  bool bRes = true;

  SParserFrame OldFrame = Parser.BeginFrame(Frame);

  FX_BEGIN_TOKENS
    FX_TOKEN(RenderOrder)
    FX_TOKEN(ProcessOrder)
    FX_TOKEN(RenderCamera)
    FX_TOKEN(RenderType)
    FX_TOKEN(RenderFilter)
    FX_TOKEN(RenderColorTarget1)
    FX_TOKEN(RenderDepthStencilTarget)
    FX_TOKEN(ClearSetColor)
    FX_TOKEN(ClearSetDepth)
    FX_TOKEN(ClearTarget)
    FX_TOKEN(RenderTarget_IDPool)
    FX_TOKEN(RenderTarget_UpdateType)
    FX_TOKEN(RenderTarget_Width)
    FX_TOKEN(RenderTarget_Height)
    FX_TOKEN(GenerateMips)
  FX_END_TOKENS

  SHRenderTarget *pRt = new SHRenderTarget;
  int nIndex;

  while (Parser.ParseObject(sCommands, nIndex))
  {
    EToken eT = Parser.GetToken();
    switch (eT)
    {
      case eT_RenderOrder:
        {
          eT = Parser.GetToken(Parser.m_Data);
          if (eT == eT_PreProcess)
            pRt->m_eOrder = eRO_PreProcess;
          else
          if (eT == eT_PostProcess)
            pRt->m_eOrder = eRO_PostProcess;
          else
          if (eT == eT_PreDraw)
            pRt->m_eOrder = eRO_PreDraw;
          else
          {
            assert(0);
            Warning("Unknown RenderOrder type '%s'", Parser.GetString(eT));
          }
        }
        break;

      case eT_ProcessOrder:
        {
          eT = Parser.GetToken(Parser.m_Data);
          if (eT == eT_WaterReflection)
            pRt->m_nProcessFlags = FSPR_SCANTEXWATER;
          else
          {
            assert(0);
            Warning("Unknown ProcessOrder type '%s'", Parser.GetString(eT));
          }
        }
        break;

      case eT_RenderCamera:
        {
          eT = Parser.GetToken(Parser.m_Data);
          if (eT == eT_WaterPlaneReflected)
            pRt->m_nFlags |= FRT_CAMERA_REFLECTED_WATERPLANE;
          else
          if (eT == eT_PlaneReflected)
            pRt->m_nFlags |= FRT_CAMERA_REFLECTED_PLANE;
          else
          if (eT == eT_Current)
            pRt->m_nFlags |= FRT_CAMERA_CURRENT;
          else
          {
            assert(0);
            Warning("Unknown RenderCamera type '%s'", Parser.GetString(eT));
          }
        }
        break;

      case eT_GenerateMips:
        pRt->m_nFlags |= FRT_GENERATE_MIPS;
        break;

      case eT_RenderType:
        {
          eT = Parser.GetToken(Parser.m_Data);
          if (eT == eT_CurObject)
            pRt->m_nFlags |= FRT_RENDTYPE_CUROBJECT;
          else
          if (eT == eT_CurScene)
            pRt->m_nFlags |= FRT_RENDTYPE_CURSCENE;
          else
          if (eT == eT_RecursiveScene)
            pRt->m_nFlags |= FRT_RENDTYPE_RECURSIVECURSCENE;
          else
          if (eT == eT_CopyScene)
            pRt->m_nFlags |= FRT_RENDTYPE_COPYSCENE;
          else
          {
            assert(0);
            Warning("Unknown RenderType type '%s'", Parser.GetString(eT));
          }
        }
        break;

      case eT_RenderFilter:
        {
          eT = Parser.GetToken(Parser.m_Data);
          if (eT == eT_Refractive)
            pRt->m_nFilterFlags |= FRF_REFRACTIVE;
// 		  else
// 		  if (eT == eT_ForceRefractionUpdate)
// 			  pRt->m_nFilterFlags |= FRF_FORCEREFRACTIVEUPDATE;
          else
          if (eT == eT_Glow)
            pRt->m_nFilterFlags |= FRF_GLOW;
          else
          if (eT == eT_Heat)
            pRt->m_nFilterFlags |= FRF_HEAT;
          else
          {
            assert(0);
            Warning("Unknown RenderFilter type '%s'", Parser.GetString(eT));
          }
        }
        break;

      case eT_RenderDepthStencilTarget:
        {
          eT = Parser.GetToken(Parser.m_Data);
          if (eT == eT_DepthBuffer || eT == eT_DepthBufferTemp)
            pRt->m_bTempDepth = true;
          else
          if (eT == eT_DepthBufferOrig)
            pRt->m_bTempDepth = false;
          else
          {
            assert(0);
            Warning("Unknown RenderDepthStencilTarget type '%s'", Parser.GetString(eT));
          }
        }
        break;

      case eT_RenderTarget_IDPool:
        pRt->m_nIDInPool = Parser.GetInt(Parser.GetToken(Parser.m_Data));
        assert(pRt->m_nIDInPool >= 0 && pRt->m_nIDInPool < 64);
        break;

      case eT_RenderTarget_Width:
        {
          eT = Parser.GetToken(Parser.m_Data);
          if (eT == eT_$ScreenSize)
            pRt->m_nWidth = -1;
          else
            pRt->m_nWidth = Parser.GetInt(eT);
        }
        break;

      case eT_RenderTarget_Height:
        {
          eT = Parser.GetToken(Parser.m_Data);
          if (eT == eT_$ScreenSize)
            pRt->m_nHeight = -1;
          else
            pRt->m_nHeight = Parser.GetInt(eT);
        }
        break;

      case eT_RenderTarget_UpdateType:
        {
          eT = Parser.GetToken(Parser.m_Data);
          if (eT == eT_WaterReflect)
            pRt->m_eUpdateType = eRTUpdate_WaterReflect;
          else
          if (eT == eT_Allways)
            pRt->m_eUpdateType = eRTUpdate_Always;
          else
            assert(0);
        }
        break;

      case eT_ClearSetColor:
        {
          eT = Parser.GetToken(Parser.m_Data);
          if (eT == eT_FogColor)
            pRt->m_nFlags |= FRT_CLEAR_FOGCOLOR;
          else
          {
            string sStr = Parser.GetString(Parser.m_Data);
            shGetColor(sStr.c_str(), pRt->m_ClearColor);
          }
        }
        break;

      case eT_ClearSetDepth:
        pRt->m_fClearDepth = Parser.GetFloat(Parser.m_Data);
        break;

      case eT_ClearTarget:
        {
          eT = Parser.GetToken(Parser.m_Data);
          if (eT == eT_Color)
            pRt->m_nFlags |= FRT_CLEAR_COLOR;
          else
          if (eT == eT_Depth)
            pRt->m_nFlags |= FRT_CLEAR_DEPTH;
          else
          {
            assert(0);
            Warning("Unknown ClearTarget type '%s'", Parser.GetString(eT));
          }
        }
        break;

      default:
        assert(0);
    }
  }
  if (pRt->m_eOrder == eRO_PreProcess)
    Parser.m_pCurShader->m_Flags |= EF_PRECACHESHADER;
  pSampler->m_pTarget = pRt;
  pSampler->PostLoad();

  Parser.EndFrame(OldFrame);

  return bRes;
}

bool CShaderManBin::ParseBinFX_Sampler_Annotations(CParserBin& Parser, SParserFrame& Annotations, STexSamplerFX *pSampler)
{
  bool bRes = true;

  SParserFrame OldFrame = Parser.BeginFrame(Annotations);

  FX_BEGIN_TOKENS
    FX_TOKEN(string)
  FX_END_TOKENS

  int nIndex = 0;

  while (Parser.ParseObject(sCommands, nIndex))
  {
    EToken eT = Parser.GetToken();
    SCodeFragment Fr;
    switch (eT)
    {
      case eT_string:
        {
          eT = Parser.GetToken(Parser.m_Name);
          assert(eT == eT_Script);
          bRes &= ParseBinFX_Sampler_Annotations_Script(Parser, Parser.m_Data, pSampler);
        }
        break;

      default:
        assert(0);
    }
  }

  Parser.EndFrame(OldFrame);

  return bRes;
}

bool CShaderManBin::ParseBinFX_Sampler(CParserBin& Parser, SParserFrame& Frame, uint32 dwName, SParserFrame Annotations)
{
  bool bRes = true;

  SParserFrame OldFrame = Parser.BeginFrame(Frame);

  FX_BEGIN_TOKENS
    FX_TOKEN(Texture)
    FX_TOKEN(MinFilter)
    FX_TOKEN(MagFilter)
    FX_TOKEN(MipFilter)
    FX_TOKEN(AddressU)
    FX_TOKEN(AddressV)
    FX_TOKEN(AddressW)
    FX_TOKEN(BorderColor)
    FX_TOKEN(AnisotropyLevel)
    FX_TOKEN(sRGBLookup)
    FX_TOKEN(Global)
  FX_END_TOKENS

  STexSamplerFX samp;
  STexState ST;
  DWORD dwBorderColor = 0;
  uint32 nFiltMin = 0;
  uint32 nFiltMip = 0;
  uint32 nFiltMag = 0;
  uint32 nAddressU = 0;
  uint32 nAddressV = 0;
  uint32 nAddressW = 0;
  uint32 nAnisotropyLevel = 0;

  int nIndex = -1;

  while (Parser.ParseObject(sCommands, nIndex))
  {
    EToken eT = Parser.GetToken();
    switch (eT)
    {
      case eT_Texture:
        samp.m_szTexture = Parser.GetString(Parser.m_Data);
        break;

      case eT_BorderColor:
        {
          string Str = Parser.GetString(Parser.m_Data);
          ColorF colBorder = Col_Black;
          shGetColor(Str.c_str(), colBorder);
          dwBorderColor = colBorder.pack_argb8888();
          ST.m_bActive = true;
        }
        break;

      case eT_sRGBLookup:
        ST.m_bSRGBLookup = Parser.GetBool(Parser.m_Data);
        break;

      case eT_Global:
#if defined (DIRECT3D9) || defined(PS3) || defined(XENON) 
        samp.m_nTexFlags |= FSAMP_GLOBAL;
#endif
        break;

      case eT_AnisotropyLevel:
        nAnisotropyLevel = Parser.GetToken(Parser.m_Data);
        break;

      case eT_MinFilter:
        nFiltMin = Parser.GetToken(Parser.m_Data);
        ST.m_bActive = true;
        break;
      case eT_MagFilter:
        nFiltMag = Parser.GetToken(Parser.m_Data);
        ST.m_bActive = true;
        break;
      case eT_MipFilter:
        nFiltMip = Parser.GetToken(Parser.m_Data);
        ST.m_bActive = true;
        break;
      case eT_AddressU:
        nAddressU = sGetTAddress(Parser.GetToken(Parser.m_Data));
        ST.m_bActive = true;
        break;
      case eT_AddressV:
        nAddressV = sGetTAddress(Parser.GetToken(Parser.m_Data));
        ST.m_bActive = true;
        break;
      case eT_AddressW:
        nAddressW = sGetTAddress(Parser.GetToken(Parser.m_Data));
        ST.m_bActive = true;
        break;

    default:
      assert(0);
    }
  }

  samp.m_szName = Parser.GetString(dwName);
  if (nFiltMag > 0 && nFiltMin > 0 && nFiltMip > 0)
  {
    if (nFiltMag == eT_LINEAR && nFiltMin == eT_LINEAR && nFiltMip == eT_LINEAR)
      ST.SetFilterMode(FILTER_TRILINEAR);
    else
    if (nFiltMag == eT_LINEAR && nFiltMin == eT_LINEAR && nFiltMip == eT_POINT)
      ST.SetFilterMode(FILTER_BILINEAR);
    else
    if (nFiltMag == eT_LINEAR && nFiltMin == eT_LINEAR && nFiltMip == eT_NONE)
      ST.SetFilterMode(FILTER_LINEAR);
    else
		if (nFiltMag == eT_POINT && nFiltMin == eT_POINT && nFiltMip == eT_POINT)
			ST.SetFilterMode(FILTER_POINT);
		else
		if (nFiltMag == eT_POINT && nFiltMin == eT_POINT && nFiltMip == eT_NONE)
			ST.SetFilterMode(FILTER_NONE);
    else
    if (nFiltMag == eT_ANISOTROPIC || nFiltMin == eT_ANISOTROPIC)
    {
      if (nAnisotropyLevel == eT_0+4)
        ST.SetFilterMode(FILTER_ANISO4X);
      else
      if (nAnisotropyLevel == eT_0+8)
        ST.SetFilterMode(FILTER_ANISO8X);
      else
      if (nAnisotropyLevel == eT_0+16)
        ST.SetFilterMode(FILTER_ANISO16X);
      else
        ST.SetFilterMode(FILTER_ANISO2X);
    }
    else
    {
      Warning("!Unknown sampler filter mode (Min=%s, Mag=%s, Mip=%s) for sampler '%s'", Parser.GetString(nFiltMin), Parser.GetString(nFiltMag), Parser.GetString(nFiltMip), samp.m_szName.c_str());
      assert(0);
    }
  }
  else
    ST.SetFilterMode(-1);

  ST.SetClampMode(nAddressU, nAddressV, nAddressW);
  ST.SetBorderColor(dwBorderColor);
  samp.m_nTexState = CTexture::GetTexState(ST);
  if (!Annotations.IsEmpty())
    bRes &= ParseBinFX_Sampler_Annotations(Parser, Annotations, &samp);
  mfAddFXSampler(Parser.m_pCurShader, &samp);

  Parser.EndFrame(OldFrame);

  return bRes;
}

/*bool CShaderManBin::AddToStaticInstCBTemplate(CParserBin& Parser, SFXParam *pParam)
{
  bool bRes = true;

  CShader *pSH = Parser.m_pCurShader;
  assert (pParam->m_nCB == CB_STATIC_INSTANCE);
  if (pParam->m_nCB != CB_STATIC_INSTANCE || pParam->m_nRegister[0] < 0 || pParam->m_nRegister[0] >= 8)
  {
    assert(0);
    if (pParam->m_nCB == CB_STATIC_INSTANCE)
      pParam->m_nCB = CB_PER_INSTANCE;
    return false;
  }
  SCGParam pr;
  bool bComp = gRenDev->m_cEF.mfParseParamComp(-1, &pr, pParam->m_Assign.c_str(), NULL, NULL, NULL, pSH, pParam->GetParamFlags(), eHWSC_Vertex, false);
  if (!bComp)
    return false;
  pr.m_dwBind = pParam->m_nRegister[0];
#if defined (DIRECT3D10) || defined(PS3)
  pr.m_dwCBufSlot = -1;
#endif
  uint32 i;
  for (i=0; i<pSH->m_InstParams.size(); i++)
  {
    SCGParam& IP = pSH->m_InstParams[i];
    if (IP.m_dwBind == pr.m_dwBind)
    {
      assert(IP.m_eCGParamType == pr.m_eCGParamType);
      break;
    }
  }
  if (i == pSH->m_InstParams.size())
  {
    pSH->m_InstParams.push_back(pr);
  }

  return bRes;
}*/

void CShaderManBin::AddAffectedParameter(CParserBin& Parser, std::vector<SFXParam>& AffectedParams, TArray<int>& AffectedFunc, SFXParam *pParam, EHWShaderClass eSHClass, uint32 dwType, SShaderTechnique *pShTech)
{
  if (!strnicmp(pParam->m_Name.c_str(), "TessellationFactor", 18))
  {
    int nnn = 0;
  }
  static uint32 eT_ShadowGen[] = {CParserBin::GetCRC32("ShadowGenVS"), CParserBin::GetCRC32("ShadowGenPS"), CParserBin::GetCRC32("ShadowGenGS")};

  if (!CParserBin::PlatformSupportsConstantBuffers()) // CAFE FIX ME ? 
  {
    //if (pParam->m_Name.c_str()[0] != '_')
    {
      if (!(Parser.m_pCurShader->m_Flags & EF_LOCALCONSTANTS))
      {
        if (pParam->m_nRegister[eSHClass]>=0 && pParam->m_nRegister[eSHClass]<10000 && pParam->m_nCB != CB_STATIC_INSTANCE)
        {
          if (pParam->m_nCB == CB_PER_SHADOWGEN && dwType != eT_ShadowGen[eSHClass])
            return;
          if ((pShTech->m_Flags & FHF_NOLIGHTS) && pParam->m_nCB == CB_PER_LIGHT)
            return;
          if ((pShTech->m_Flags & FHF_NOLIGHTS) && pParam->m_nCB == CB_PER_MATERIAL && !(pParam->m_nFlags & PF_TWEAKABLE_MASK))
            return;
          if (pParam->m_Assign.empty() && pParam->m_Values.c_str()[0] == '(')
            pParam->m_nCB = CB_PER_MATERIAL;
          AffectedParams.push_back(*pParam);
          return;
        }
      }
    }
  }
  else
  if (pParam->m_nCB == CB_PER_LIGHT || pParam->m_nCB == CB_PER_MATERIAL || pParam->m_nCB == CB_PER_FRAME || pParam->m_nCB == CB_PER_SHADOWGEN)
  {
    if (pParam->m_nRegister[eSHClass]<0 || pParam->m_nRegister[eSHClass]>=1000)
      return;
  }

  int nFlags = pParam->GetParamFlags();
  bool bCheckAffect = CParserBin::m_bParseFX ? true : false;
  if (nFlags & PF_ALWAYS)
    AffectedParams.push_back(*pParam);
  else
  {
    if (CParserBin::m_nPlatform == SF_D3D11 || CParserBin::m_nPlatform == SF_D3D10) // CAFE FIX ME , what does this do?
    {
      assert(eSHClass < eHWSC_Num);
      if (((nFlags & PF_TWEAKABLE_MASK) || pParam->m_Values.c_str()[0] == '(') && pParam->m_nRegister[eSHClass]>=0 && pParam->m_nRegister[eSHClass]<1000)
        bCheckAffect = false;
    }
    for (uint32 j=0; j<AffectedFunc.size(); j++)
    {
      SCodeFragment *pCF = &Parser.m_CodeFragments[AffectedFunc[j]];
      if (!bCheckAffect || Parser.FindToken(pCF->m_nFirstToken, pCF->m_nLastToken, pParam->m_dwName[0]) >= 0)
      {
        AffectedParams.push_back(*pParam);
        break;
      }
    }
  }
}

static int gFind;
void CShaderManBin::CheckFunctionsAffect_r(CParserBin& Parser, SCodeFragment *pFunc, TArray<byte>& bChecked, TArray<int>& AffectedFunc)
{
  uint32 i;
  uint32 numFrags = Parser.m_CodeFragments.size();

  for (i=0; i<numFrags; i++)
  {
    if (bChecked[i])
      continue;
    SCodeFragment *s = &Parser.m_CodeFragments[i];
    if (!s->m_dwName)
    {
      bChecked[i] = 1;
      continue;
    }
    if (s->m_eType != eFT_Function)
      continue;

    gFind++;
    if (Parser.FindToken(pFunc->m_nFirstToken, pFunc->m_nLastToken, s->m_dwName) >= 0)
    {
      bChecked[i] = 1;
      AffectedFunc.push_back(i);
      CheckFunctionsAffect_r(Parser, s, bChecked, AffectedFunc);
    }
  }
}

void CShaderManBin::CheckStructureAffect_r(CParserBin& Parser, SCodeFragment *pFrag, TArray<byte>& bChecked, TArray<int>& AffectedFunc)
{
  uint32 i;
  uint32 numFrags = Parser.m_CodeFragments.size();

  for (i=0; i<numFrags; i++)
  {
    if (bChecked[i])
      continue;
    SCodeFragment *s = &Parser.m_CodeFragments[i];
    if (s->m_eType != eFT_Structure)
      continue;

    gFind++;
    if (Parser.FindToken(pFrag->m_nFirstToken, pFrag->m_nLastToken, s->m_dwName) >= 0)
    {
      bChecked[i] = 1;
      AffectedFunc.push_back(i);
      CheckStructureAffect_r(Parser, s, bChecked, AffectedFunc);
    }
  }
}

void CShaderManBin::CheckFragmentsAffect_r(CParserBin& Parser, TArray<byte>& bChecked, TArray<int>& AffectedFrags)
{
  uint32 i, j;
  const uint32 numFuncs = AffectedFrags.size();
  const uint32 numFrags = Parser.m_CodeFragments.size();

  for (i=0; i<numFuncs; i++)
  {
    int nFunc = AffectedFrags[i];
    SCodeFragment *pFunc = &Parser.m_CodeFragments[nFunc];
    for (j=0; j<numFrags; j++)
    {
      SCodeFragment *s = &Parser.m_CodeFragments[j];
      if (bChecked[j])
        continue;
      if (s->m_eType != eFT_Sampler && s->m_eType != eFT_Structure)
        continue;

      gFind++;
      if (Parser.FindToken(pFunc->m_nFirstToken, pFunc->m_nLastToken, s->m_dwName) >= 0)
      {
        bChecked[j] = 1;
        AffectedFrags.push_back(j);
        if (s->m_eType == eFT_Structure)
          CheckStructureAffect_r(Parser, s, bChecked, AffectedFrags);
      }
    }
  }
}

//=================================================================================================

struct SFXRegisterBin
{
  int nReg;
  int nComp;
  int m_nCB;
  uint32 m_nFlags;
  EParamType eType;
  uint32 dwName;
  CCryNameR m_Value;
  SFXRegisterBin()
  {
    eType = eType_UNKNOWN;
    m_nCB = -1;
  }
};

struct SFXPackedName
{
  uint32 dwName[4];

  SFXPackedName()
  {
    dwName[0] = dwName[1] = dwName[2] = dwName[3] = 0;
  }
};

inline bool Compar(const SFXRegisterBin &a, const SFXRegisterBin &b)
{
  if (CParserBin::PlatformSupportsConstantBuffers())
  {
    if(a.m_nCB != b.m_nCB)
      return a.m_nCB < b.m_nCB;
  }
  if(a.nReg != b.nReg)
    return a.nReg < b.nReg;
  if(a.nComp != b.nComp)
    return a.nComp < b.nComp;
  return false;
}

static void sFlushRegs(CParserBin& Parser, int nReg, SFXRegisterBin *MergedRegs[4], std::vector<SFXParam>& NewParams, EHWShaderClass eSHClass, std::vector<SFXPackedName>& PackedNames)
{
  NewParams.resize(NewParams.size()+1);
  PackedNames.resize(PackedNames.size()+1);
  SFXParam& p = NewParams[NewParams.size()-1];
  SFXPackedName& pN = PackedNames[PackedNames.size()-1];
  int nMaxComp = -1;
  int j;

  int nCompMerged = 0;
  EParamType eType = eType_UNKNOWN;
  int nCB = -1;
  for (j=0; j<4; j++)
  {
    if (MergedRegs[j] && MergedRegs[j]->eType != eType_UNKNOWN)
    {
      if (nCB == -1)
        nCB = MergedRegs[j]->m_nCB;
      else
      if (nCB != MergedRegs[j]->m_nCB)
      {
        assert(0);
      }
      if (eType == eType_UNKNOWN)
        eType = MergedRegs[j]->eType;
      else
      if (eType != MergedRegs[j]->eType)
      {
        //assert(0);
      }
    }
  }
  for (j=0; j<4; j++)
  {
	char s[16];
	if(CParserBin::m_nPlatform==SF_CAFE) 	//don't use double underscore __ // CAFE FIX ME
	{
		int nameLength = p.m_Name.length();
		if(nameLength == 0 || p.m_Name.c_str()[nameLength-1]!='_')
		{
			p.m_Name = stack_string(p.m_Name.c_str()) + '_';
		}
		sprintf(s, "%d", j);
	}
	else
	{
		sprintf(s, "__%d", j);
	}
	p.m_Name = stack_string(p.m_Name.c_str()) + s;
    if (MergedRegs[j])
    {
      if (MergedRegs[j]->m_nFlags & PF_TWEAKABLE_MASK)
        p.m_nFlags |= (PF_TWEAKABLE_0 << j);
      p.m_nFlags |= MergedRegs[j]->m_nFlags & ~(PF_TWEAKABLE_MASK | PF_SCALAR | PF_SINGLE_COMP | PF_MERGE_MASK);
      nMaxComp = max(nMaxComp, j);
      pN.dwName[j] = MergedRegs[j]->dwName;
      if (nCompMerged)
      {
        p.m_Values = stack_string(p.m_Values.c_str()) += ", ";
      }
      p.m_Name = stack_string(p.m_Name.c_str()) + Parser.GetString(pN.dwName[j]);
      p.m_Values = stack_string(p.m_Values.c_str()) + MergedRegs[j]->m_Value.c_str();
      nCompMerged++;
    }
    else
    {
      if (nCompMerged)
        p.m_Values = stack_string(p.m_Values.c_str()) + ", ";
      p.m_Values = stack_string(p.m_Values.c_str()) + "NULL";
      nCompMerged++;
    }
  }
  p.m_nComps = nMaxComp+1;
#if !defined(PS3) && !defined(XENON) && !defined(CAFE)
  if (CParserBin::m_nPlatform!=SF_D3D10 && CParserBin::m_nPlatform!=SF_D3D11 && eSHClass == eHWSC_Geometry)
    return;
  if (CParserBin::m_nPlatform!=SF_D3D11 && eSHClass == eHWSC_Domain)
    return;
  if (CParserBin::m_nPlatform!=SF_D3D11 && eSHClass == eHWSC_Hull)
    return;
  if (CParserBin::m_nPlatform!=SF_D3D11 && eSHClass == eHWSC_Compute)
    return;
#endif

  // Get packed name token.
  p.m_dwName.push_back(Parser.NewUserToken(eT_unknown, p.m_Name.c_str(), true)); //pass by crysting so that string references work.
  assert(eSHClass < eHWSC_Num);
  p.m_nRegister[eSHClass] = nReg;
#if !defined(PS3) && !defined(XENON) && !defined(CAFE)
  if (eSHClass == eHWSC_Domain || eSHClass == eHWSC_Hull || eSHClass == eHWSC_Compute)
    p.m_nRegister[eHWSC_Vertex] = nReg;
#endif
  p.m_nParameters = 1;
  if (eType == eType_HALF)
    eType = eType_FLOAT;
  p.m_eType = eType;
  assert(eType != eType_UNKNOWN);
  p.m_nCB = nCB;
  p.m_nFlags |= PF_AUTOMERGED;
}

static EToken sCompToken[4] = {eT_x, eT_y, eT_z, eT_w};
bool CShaderManBin::ParseBinFX_Technique_Pass_PackParameters (CParserBin& Parser, std::vector<SFXParam>& AffectedParams, TArray<int>& AffectedFunc, SCodeFragment *pFunc, EHWShaderClass eSHClass, uint32 dwSHName, std::vector<SFXParam>& PackedParams, TArray<SCodeFragment>& Replaces, TArray<uint32>& NewTokens, TArray<byte>& bMerged)
{
  bool bRes = true;

  uint32 i, j;

  std::vector<SFXRegisterBin> Registers;
  std::vector<SFXPackedName> PackedNames;
  uint32 nMergeMask = (eSHClass == eHWSC_Pixel) ? 1 : 2;
  for (i=0; i<AffectedParams.size(); i++)
  {
    SFXParam *pr = &AffectedParams[i];
    if (pr->m_Annotations.empty())
      continue;  // Parameter doesn't have custom register definition
    if (bMerged[i] & nMergeMask)
      continue;
    bMerged[i] |= nMergeMask;
    char *src = (char *)pr->m_Annotations.c_str();
    char annot[256];
    while (true)
    {
      fxFill(&src, annot);
      if (!annot[0])
        break;
      if (strncmp(&annot[1], "sregister", 9)) 
        break;
      if ((eSHClass == eHWSC_Pixel && annot[0] != 'p') || (eSHClass == eHWSC_Vertex && annot[0] != 'v')
#if !defined(PS3) && !defined(XENON) && !defined(CAFE)
        || (eSHClass == eHWSC_Geometry && annot[0] != 'g') || (eSHClass == eHWSC_Hull && annot[0] != 'h') || (eSHClass == eHWSC_Domain && annot[0] != 'd') || (eSHClass == eHWSC_Compute && annot[0] != 'c'))


#endif
        continue;
      char *b = &annot[10];
      SkipCharacters (&b, kWhiteSpace);
      assert(b[0] == '=');
      b++;
      SkipCharacters (&b, kWhiteSpace);
      assert(b[0] == 'c');
      if (b[0] == 'c')
      {
        int nReg = atoi(&b[1]);
        b++;
        while (*b != '.')
        {
          if (*b == 0) // Vector without swizzling
            break;
          b++;
        }
        if (*b == '.')
        {
          bMerged[i] |= (nMergeMask << 4);
          b++;
          int nComp = -1;
          switch(b[0])
          {
          case 'x':
          case 'r': nComp = 0; break;
          case 'y':
          case 'g': nComp = 1; break;
          case 'z':
          case 'b': nComp = 2; break;
          case 'w':
          case 'a': nComp = 3; break;
          default:
            assert(0);
          }
          if (nComp >= 0)
          {
            pr->m_nFlags |= (nMergeMask << PF_MERGE_SHIFT);
            SFXRegisterBin rg;
            rg.nReg = nReg;
            rg.nComp = nComp;
            rg.dwName = pr->m_dwName[0];
            rg.m_Value = pr->m_Values;
            rg.m_nFlags = pr->m_nFlags;
            rg.eType = (EParamType)pr->m_eType;
            rg.m_nCB = pr->m_nCB;
            assert(rg.m_Value.c_str()[0]);
            Registers.push_back(rg);
          }
        }
      }
      break;
    }
  }
  if (Registers.empty())
    return false;
  std::sort(Registers.begin(), Registers.end(), Compar);
  int nReg = -1;
  int nCB = -1;
  SFXRegisterBin *MergedRegs[4];
  MergedRegs[0] = MergedRegs[1] = MergedRegs[2] = MergedRegs[3] = NULL;
  for (i=0; i<Registers.size(); i++)
  {
    SFXRegisterBin *rg = &Registers[i];

	if ((!CParserBin::PlatformSupportsConstantBuffers() && rg->nReg != nReg) || (CParserBin::PlatformSupportsConstantBuffers() && (rg->m_nCB != nCB || rg->nReg != nReg)))
    {
      if (nReg >= 0)
        sFlushRegs(Parser, nReg, MergedRegs, PackedParams, eSHClass, PackedNames);
      nReg = rg->nReg;
      nCB = rg->m_nCB;
      MergedRegs[0] = MergedRegs[1] = MergedRegs[2] = MergedRegs[3] = NULL;
    }
    assert(!MergedRegs[rg->nComp]);
    if (MergedRegs[rg->nComp])
    {
      Warning("register c%d (comp: %d) is used by the %s shader '%s' already", rg->nReg, rg->nComp, eSHClass==eHWSC_Pixel ? "pixel" : "vertex", Parser.GetString(dwSHName));
      assert(0);
    }
    MergedRegs[rg->nComp] = rg;
  }
  if (MergedRegs[0] || MergedRegs[1] || MergedRegs[2] || MergedRegs[3])
    sFlushRegs(Parser, nReg, MergedRegs, PackedParams, eSHClass, PackedNames);

  // Replace new parameters in shader tokens
  for (uint32 n=0; n<AffectedFunc.size(); n++)
  {
    SCodeFragment *st = &Parser.m_CodeFragments[AffectedFunc[n]];
    const char *szName = Parser.GetString(st->m_dwName);

    for (i=0; i<PackedParams.size(); i++)
    {
      SFXParam *pr = &PackedParams[i];
      SFXPackedName *pn = &PackedNames[i];
      for (j=0; j<4; j++)
      {
        uint32 nP = pn->dwName[j];
        if (nP == 0)
          continue;
        int32 nPos = st->m_nFirstToken;
        while (true)
        {
          nPos = Parser.FindToken(nPos, st->m_nLastToken, nP);
          if (nPos < 0)
            break;
          SCodeFragment Fr;
          Fr.m_nFirstToken = Fr.m_nLastToken = nPos;
          Fr.m_dwName = n;
          Replaces.push_back(Fr);

          Fr.m_nFirstToken = NewTokens.size();
          NewTokens.push_back(pr->m_dwName[0]);
          NewTokens.push_back(eT_dot);
          NewTokens.push_back(sCompToken[j]);
          Fr.m_nLastToken = NewTokens.size()-1;
          Replaces.push_back(Fr);
          nPos++;
        }
      }
    }
  }

  for (i=0; i<Replaces.size(); i+=2)
  {
    SCodeFragment *pFR1 = &Replaces[i];
    for (j=i+2; j<Replaces.size(); j+=2)
    {
      SCodeFragment *pFR2 = &Replaces[j];
      if (pFR1->m_dwName != pFR2->m_dwName)
        continue;
      if (pFR2->m_nFirstToken < pFR1->m_nFirstToken)
      {
        std::swap(Replaces[i], Replaces[j]);
        std::swap(Replaces[i+1], Replaces[j+1]);
      }
    }
  }

  return bRes;
}

//===================================================================================================

inline bool CompareVars(const SFXParam *a, const SFXParam *b)
{
  uint16 nCB0 = CB_NUM;
  uint16 nCB1 = CB_NUM;
  int16 nReg0 = 10000;
  int16 nReg1 = 10000;
  nCB0 = a->m_nCB;
  nReg0 = a->m_nRegister[gRenDev->m_RP.m_FlagsShader_LT];

  nCB1 = b->m_nCB;
  nReg1 = b->m_nRegister[gRenDev->m_RP.m_FlagsShader_LT];

  if (nCB0 != nCB1)
    return (nCB0 < nCB1);
  return (nReg0 < nReg1);
}
EToken dwNamesCB[CB_NUM] = {eT_PER_BATCH, eT_PER_INSTANCE, eT_STATIC_INSTANCE, eT_PER_FRAME, eT_PER_MATERIAL, eT_PER_LIGHT, eT_PER_SHADOWGEN, eT_SKIN_DATA, eT_SHAPE_DATA, eT_INSTANCE_DATA};

void CShaderManBin::AddParameterToScript(CParserBin& Parser, SFXParam *pr, PodArray<uint32>& SHData, EHWShaderClass eSHClass, int nCB, uint32 * pPrevReg)
{
  char str[256];
  int nReg = pr->m_nRegister[eSHClass];

  bool bPackOffset = false;

  if (nCB == CB_PER_MATERIAL || nCB == CB_PER_FRAME || nCB == CB_PER_LIGHT || nCB == CB_PER_SHADOWGEN || nCB == CB_STATIC_INSTANCE)
  {
	  bPackOffset = true;
  }
#if !defined(XENON) && !defined(PS3) && !defined(CAFE)
  if(CParserBin::m_nPlatform == SF_CAFE && bPackOffset) // Padding hack
  {
	  uint32 nPrevReg = *pPrevReg;
	  int padRequired  = nReg - nPrevReg;

	  for(int i = 0; i < padRequired; i++)
	  {
		  SHData.push_back(eT_float4);

		  sprintf(str, "padding_%d_%d", nCB, i+nPrevReg);
		  SHData.push_back(Parser.NewUserToken(eT_unknown, str, true));

		  SHData.push_back(eT_semicolumn);
	  }

	  *pPrevReg = nReg + pr->m_nParameters;
  }
#endif

  if (pr->m_eType == eType_BOOL)
    SHData.push_back(eT_bool);
  else
  if (pr->m_eType == eType_INT)
    SHData.push_back(eT_int);
  else
  {
    int nVal = pr->m_nParameters*4+pr->m_nComps;
    EToken eT = eT_unknown;
    switch (nVal)
    {
      case 4+1:
        eT = (pr->m_eType == eType_FLOAT)? eT_float : eT_half;
        break;
      case 4+2:
        //eT = eT_float2;
        eT = (pr->m_eType == eType_FLOAT)? eT_float2 : eT_half2;
        break;
      case 4+3:
        //eT = eT_float3;
        eT = (pr->m_eType == eType_FLOAT)? eT_float3 : eT_half3;
        break;
      case 4+4:
        //eT = eT_float4;
        eT = (pr->m_eType == eType_FLOAT)? eT_float4 : eT_half4;
        break;
      case 2*4+4:
        //eT = eT_float2x4;
        eT = (pr->m_eType == eType_FLOAT)? eT_float2x4 : eT_half2x4;
        break;
      case 3*4+4:
        //eT = eT_float3x4;
        eT = (pr->m_eType == eType_FLOAT)? eT_float3x4 : eT_half3x4;
        break;
      case 4*4+4:
        //eT = eT_float4x4;
        eT = (pr->m_eType == eType_FLOAT)? eT_float4x4 : eT_half4x4;
        break;
      case 3*4+3:
        //eT = eT_float3x3;
        eT = (pr->m_eType == eType_FLOAT)? eT_float3x3: eT_half3x3;
        break;
    }
    assert(eT != eT_unknown);
    if (eT == eT_unknown)
      return;
    SHData.push_back(eT);
  }
  for (uint32 i=0; i<pr->m_dwName.size(); i++)
    SHData.push_back(pr->m_dwName[i]);

  if (nReg>=0 && nReg<10000 && CParserBin::m_nPlatform != SF_CAFE)
  {
    SHData.push_back(eT_colon);
    if (nCB == CB_PER_MATERIAL || nCB == CB_PER_FRAME || nCB == CB_PER_LIGHT || nCB == CB_PER_SHADOWGEN || nCB == CB_STATIC_INSTANCE)
      SHData.push_back(eT_packoffset);
    else
      SHData.push_back(eT_register);
    SHData.push_back(eT_br_rnd_1);
    sprintf(str, "c%d", nReg);
    SHData.push_back(Parser.NewUserToken(eT_unknown, str, true));
    SHData.push_back(eT_br_rnd_2);
  }
  SHData.push_back(eT_semicolumn);
	if(CParserBin::m_nPlatform == SF_PS3)
	{
		sprintf(str, "CBUFFER(%d)\n",pr->m_nCB);
		SHData.push_back(eT_comment);
		SHData.push_back(Parser.NewUserToken(eT_unknown, str, true));
	}
}

bool CShaderManBin::ParseBinFX_Technique_Pass_GenerateShaderData(CParserBin& Parser, FXMacroBin& Macros, SShaderFXParams& FXParams, uint32 dwSHName, EHWShaderClass eSHClass, uint64& nAffectMask, uint32 dwSHType, PodArray<uint32>& SHData, SShaderTechnique *pShTech)
{
	LOADING_TIME_PROFILE_SECTION(iSystem);
  assert(gRenDev->m_pRT->IsRenderThread());

	bool bRes = true;

  std::vector<SFXParam> AffectedParams;

  uint32 i, j;
	uint32 nNum;
  static TArray<int> AffectedFragments;
	AffectedFragments.reserve(120);
  AffectedFragments.SetUse(0);

  for (nNum=0; nNum<Parser.m_CodeFragments.size(); nNum++)
  {
    if (dwSHName == Parser.m_CodeFragments[nNum].m_dwName)
      break;
  }
  if (nNum == Parser.m_CodeFragments.size())
  {
    Warning("Couldn't find entry function '%s'", Parser.GetString(dwSHName));
    return false;
  }

  SCodeFragment *pFunc = &Parser.m_CodeFragments[nNum];
  SShaderBin *pBin = Parser.m_pCurBinShader;
  SParamCacheInfo *pCache = GetParamInfo(pBin, pFunc->m_dwName, Parser.m_pCurShader->m_nMaskGenFX);
  if (pCache)
  {
		AffectedFragments.SetUse(0);
		AffectedFragments.reserve(pCache->m_AffectedFuncs.size());
		if (pCache->m_AffectedFuncs.empty() == false)
			AffectedFragments.Copy(&pCache->m_AffectedFuncs[0], pCache->m_AffectedFuncs.size());
  }
  else
  {
    AffectedFragments.push_back(nNum);
    if (CParserBin::m_bParseFX)
    {
      TArray<byte> bChecked;
      bChecked.resize(Parser.m_CodeFragments.size());
      if (bChecked.size() > 0)
        memset(&bChecked[0], 0, sizeof(byte)*bChecked.size());
      bChecked[nNum] = 1;
      CheckFunctionsAffect_r(Parser, pFunc, bChecked, AffectedFragments);
      CheckFragmentsAffect_r(Parser, bChecked, AffectedFragments);
    }
    else
    {
      for (i=0; i<Parser.m_CodeFragments.size(); i++)
      {
        if (i != nNum)
				{
          AffectedFragments.push_back(i);
				}
      }
    }
  }

  nAffectMask = 0;
  for (i=0; i<AffectedFragments.size(); i++)
  {
    SCodeFragment *s = &Parser.m_CodeFragments[AffectedFragments[i]];
    if (s->m_eType != eFT_Function && s->m_eType != eFT_Structure)
      continue;
    FXMacroBinItor itor;
    for (itor=Macros.begin(); itor!=Macros.end(); ++itor)
    {
      SMacroBinFX *pr = &itor->second;
      if (!pr->m_nMask)
        continue;
      if ((pr->m_nMask & nAffectMask) == pr->m_nMask)
        continue;
      uint32 dwName = itor->first;
      if (Parser.FindToken(s->m_nFirstToken, s->m_nLastToken, dwName) >= 0)
        nAffectMask |= pr->m_nMask;
    }
  }

  // Generate list of params before first preprocessor pass for affected functions
  TArray<byte> bMerged;
  bMerged.Reserve(FXParams.m_FXParams.size());
  if (pCache)
  {
    for (i=0; i<pCache->m_AffectedParams.size(); i++)
    {
      int32 nParam = pCache->m_AffectedParams[i];
      FXParamsIt it = std::lower_bound(FXParams.m_FXParams.begin(), FXParams.m_FXParams.end(), nParam, FXParamsSortByName());
      if (it != FXParams.m_FXParams.end() && nParam == (*it).m_dwName[0])
      {
        SFXParam& pr = (*it);
        if (!(pr.GetParamFlags() & PF_AUTOMERGED))
        {
          if (pr.m_Assign.empty() && pr.m_Values.c_str()[0] == '(')
            pr.m_nCB = CB_PER_MATERIAL;
          AffectedParams.push_back(pr);
        }
      }
    }
  }
  else
  {
    for (i=0; i<FXParams.m_FXParams.size(); i++)
    {
      SFXParam *pr = &FXParams.m_FXParams[i];
      if (!(pr->GetParamFlags() & PF_AUTOMERGED))
        AddAffectedParameter(Parser, AffectedParams, AffectedFragments, pr, eSHClass, dwSHType, pShTech);
    }
  }

  if (CParserBin::m_bParseFX)
  {
    FXMacroBinItor itor;
    for (itor=Macros.begin(); itor!=Macros.end(); ++itor)
    {
      if (itor->second.m_nMask && !(itor->second.m_nMask & nAffectMask))
        continue;
      SHData.push_back(eT_define);
      SHData.push_back(itor->first);
      SHData.push_back(0);
    }
    std::vector<SFXParam> PackedParams;
    TArray<SCodeFragment> Replaces;
    TArray<uint32> NewTokens;
    ParseBinFX_Technique_Pass_PackParameters (Parser, AffectedParams, AffectedFragments, pFunc, eSHClass, dwSHName, PackedParams, Replaces, NewTokens, bMerged);

    if (!pCache)
    {
      // Update new parameters in shader structures
      for (i=0; i<PackedParams.size(); i++)
      {
        SFXParam *pr = &PackedParams[i];
        AffectedParams.push_back(*pr);
      }
      if (!CRenderer::CV_r_shadersnocompile)
        SaveBinShaderLocalInfo(pBin, pFunc->m_dwName, Parser.m_pCurShader->m_nMaskGenFX, AffectedFragments, AffectedParams);
    }
    else
    {
      for (i=0; i<pCache->m_AffectedParams.size(); i++)
      {
        int32 nParam = pCache->m_AffectedParams[i];
        for (j=0; j<PackedParams.size(); j++) 
        {
          SFXParam& pr = PackedParams[j];
          if (pr.m_dwName[0] == nParam)
          {
            AffectedParams.push_back(pr);
            break;
          }
        }
      }
    }

    // Update FX parameters
    for (i=0; i<AffectedParams.size(); i++)
    {
      SFXParam *pr = &AffectedParams[i];
      mfAddFXParam(FXParams, pr);
    }

    // Include all affected functions/structures/parameters in the final script 
	  //need CB-scopes on PS3 for correct reflection, but everything else d3d9-HLSL-style



	if (CParserBin::PlatformSupportsConstantBuffers()) // use CB scopes for D3D10 shaders

    {
      int8 nPrevCB = -1;

	  uint32 nPrevReg = 0;

      std::vector<SFXParam *> ParamsData;

      byte bMergeMask = (eSHClass == eHWSC_Pixel) ? 1 : 2;
      bMergeMask <<= 4;
      for (i=0; i<AffectedParams.size(); i++)
      {
        SFXParam &pr = AffectedParams[i];
        if (bMerged[i] & bMergeMask)
          continue;
        if (pr.m_nCB >= 0)
          ParamsData.push_back(&pr);
      }
      if (eSHClass == eHWSC_Vertex)
        gRenDev->m_RP.m_FlagsShader_LT = 0;
      else
      if (eSHClass == eHWSC_Pixel)
        gRenDev->m_RP.m_FlagsShader_LT = 1;
      else
        gRenDev->m_RP.m_FlagsShader_LT = 2;

      std::sort(ParamsData.begin(), ParamsData.end(), CompareVars);

      // First we need to declare semantic variables (in CB scopes in case of DX11)
      for (i=0; i<ParamsData.size(); i++)
      {
        SFXParam *pPr = ParamsData[i];
        int nCB = pPr->m_nCB;
        nCB = pPr->m_nCB;
        if (nPrevCB != nCB)
        {
          if (nPrevCB != -1)
          {
            SHData.push_back(eT_br_cv_2);
            SHData.push_back(eT_semicolumn);
          }
          SHData.push_back(eT_cbuffer);
          SHData.push_back(dwNamesCB[nCB]);

		  if(CParserBin::m_nPlatform != SF_CAFE)
		  {
			  SHData.push_back(eT_colon);
			  SHData.push_back(eT_register);
			  char str[32];
			  sprintf(str, "b%d", nCB);
			  SHData.push_back(eT_br_rnd_1);
			  SHData.push_back(Parser.NewUserToken(eT_unknown, str, true));
			  SHData.push_back(eT_br_rnd_2);
		  }

          SHData.push_back(eT_br_cv_1);

		  nPrevReg = 0;
        }
        nPrevCB = nCB;
        AddParameterToScript(Parser, pPr, SHData, eSHClass, nCB, &nPrevReg);
      }
      if (nPrevCB >= 0)
      {
        nPrevCB = -1;
        SHData.push_back(eT_br_cv_2);
        SHData.push_back(eT_semicolumn);
      }
    }
    else
    {
      // Update affected parameters in script
#ifdef _DEBUG
      for (i=0; i<AffectedParams.size(); i++)
      {
        SFXParam *pr = &AffectedParams[i];
        for (j=i+1; j<AffectedParams.size(); j++)
        {
          SFXParam *pr1 = &AffectedParams[j];
          if (pr->m_dwName[0] == pr1->m_dwName[0])
          {
            assert(0);
          }
        }
      }
#endif
      byte bMergeMask = (eSHClass == eHWSC_Pixel) ? 1 : 2;
      bMergeMask <<= 4;
      for (i=0; i<AffectedParams.size(); i++)
      {
        SFXParam *pr = &AffectedParams[i];
        // Ignore parameters which where packed
        if (bMerged[i] & bMergeMask)
          continue;
        AddParameterToScript(Parser, pr, SHData, eSHClass, -1);
      }
    }
     
    // Generate fragment tokens
    int h = -1;
    for (i=0; i<Parser.m_CodeFragments.size(); i++)
    {
      SCodeFragment *cf = &Parser.m_CodeFragments[i];
      if (cf->m_dwName)
      {
        for (h=0; h < (int)AffectedFragments.size(); h++)
        {
          if (AffectedFragments[h] == i)
            break;
        }
        if (h == AffectedFragments.size())
          continue;
      }

      Parser.CopyTokens(cf, SHData, Replaces, NewTokens, h);
      if (cf->m_eType == eFT_Sampler)
      {
        if (CParserBin::m_nPlatform == SF_D3D11 || CParserBin::m_nPlatform == SF_D3D10)
        {
          int nT = Parser.m_Tokens[cf->m_nLastToken-1];
          //assert(nT >= eT_s0 && nT <= eT_s15);
          if (nT >= eT_s0 && nT <= eT_s15)
          {
            nT = nT-eT_s0+eT_t0;
            SHData.push_back(eT_colon);
            SHData.push_back(eT_register);
            SHData.push_back(eT_br_rnd_1);
            SHData.push_back(nT);
            SHData.push_back(eT_br_rnd_2);
          }
        }
        SHData.push_back(eT_semicolumn);
      }
    }
  }
  return bRes;
}

bool CShaderManBin::ParseBinFX_Technique_Pass_LoadShader(CParserBin& Parser, FXMacroBin& Macros, SParserFrame& SHFrame, SShaderTechnique *pShTech, SShaderPass *pPass, EHWShaderClass eSHClass, SShaderFXParams& FXParams)
{
  assert (gRenDev->m_pRT->IsRenderThread());

	LOADING_TIME_PROFILE_SECTION(iSystem);
	bool bRes = true;

#ifndef NULL_RENDERER

  assert(!SHFrame.IsEmpty());

  uint32 dwSHName;
  uint32 dwSHType = 0;

  uint32 *pTokens = &Parser.m_Tokens[0];

  dwSHName = pTokens[SHFrame.m_nFirstToken];
  uint32 nCur = SHFrame.m_nFirstToken+1;
  uint32 nTok = pTokens[nCur];
  if (nTok != eT_br_rnd_1)
  {
    nCur += 2;
    nTok = pTokens[nCur];
  }
  nCur++;
  assert (nTok == eT_br_rnd_1);
  if (nTok == eT_br_rnd_1)
  {
    nTok = pTokens[nCur];
    if (nTok != eT_br_rnd_2)
    {
      assert(!"Local function parameters aren't supported anymore");
    }
  }
  nCur++;
  if (nCur <= SHFrame.m_nLastToken)
  {
    dwSHType = pTokens[nCur];
  }

	enum { SHDATA_BUFFER_SIZE = 12000 };

  uint64 nGenMask = 0;
	PodArray<uint32> SHDataBuffer(SHDATA_BUFFER_SIZE);
  const char *szName = Parser.GetString(dwSHName);
  bRes &= ParseBinFX_Technique_Pass_GenerateShaderData(Parser, Macros, FXParams, dwSHName, eSHClass, nGenMask, dwSHType, SHDataBuffer, pShTech);
#if !defined(_RELEASE) && !defined(CRYTEK_SDK_EVALUATION) && !defined(IS_CRYDEV)
	if (SHDataBuffer.size() > SHDATA_BUFFER_SIZE)
	{
		CryLogAlways("CShaderManBin::ParseBinFX_Technique_Pass_LoadShader: SHDataBuffer has been exceeded (buffer=%u, count=%u). Adjust buffer size to remove unnecessary allocs", SHDATA_BUFFER_SIZE, SHDataBuffer.Size());
	}
#endif
	TArray<uint32> SHData(0, SHDataBuffer.Size());
	SHData.Copy(SHDataBuffer.GetElements(), SHDataBuffer.size());
	
  CHWShader *pSH = NULL;
  bool bValidShader = false;

  CShader *efSave = gRenDev->m_RP.m_pShader;
  gRenDev->m_RP.m_pShader = Parser.m_pCurShader;
	assert(gRenDev->m_RP.m_pShader != 0);
  if (bRes && (!CParserBin::m_bParseFX || !SHData.empty()))
  {
    char str[1024];
    if (CParserBin::m_nPlatform == SF_XENON)
      sprintf(str, "%s/%s", Parser.m_pCurShader->m_NameShader.c_str(), szName);
    else
      sprintf(str, "%s@%s", Parser.m_pCurShader->m_NameShader.c_str(), szName);
    pSH = CHWShader::mfForName(str, Parser.m_pCurShader->m_NameFile, Parser.m_pCurShader->m_CRC32, szName, eSHClass, SHData, &Parser.m_TokenTable, dwSHType, Parser.m_pCurShader, nGenMask, Parser.m_pCurShader->m_nMaskGenFX);
  }
  if (pSH)
  {
    /*uint64 nFlagsOrigShader_RT = 0;
    uint64 nFlagsOrigShader_GL = pSH->m_nMaskGenShader;
    uint32 nFlagsOrigShader_LT = 0;
    pSH->mfModifyFlags(Parser.m_pCurShader);*/

    bValidShader = true;

    if (eSHClass == eHWSC_Vertex)
      pPass->m_VShader = pSH;
    else
    if (eSHClass == eHWSC_Pixel)
      pPass->m_PShader = pSH;
#if !defined (PS3) && !defined (XENON) && !defined(CAFE)
    else
    if (GEOMETRYSHADER_SUPPORT && (CParserBin::m_nPlatform==SF_D3D11 || CParserBin::m_nPlatform==SF_D3D10) && eSHClass == eHWSC_Geometry)
      pPass->m_GShader = pSH;
    else
    if (CParserBin::m_nPlatform==SF_D3D11 && eSHClass == eHWSC_Domain)
      pPass->m_DShader = pSH;
    else
    if (CParserBin::m_nPlatform==SF_D3D11 && eSHClass == eHWSC_Hull)
      pPass->m_HShader = pSH;
    else
    if (CParserBin::m_nPlatform==SF_D3D11 && eSHClass == eHWSC_Compute)
      pPass->m_CShader = pSH;
#endif
    else
      assert(0);
  }

  gRenDev->m_RP.m_pShader = efSave;
#endif

  return bRes;
}

bool CShaderManBin::ParseBinFX_Technique_Pass(CParserBin& Parser, SParserFrame& Frame, SShaderTechnique *pShTech)
{
  SParserFrame OldFrame = Parser.BeginFrame(Frame);

  FX_BEGIN_TOKENS
    FX_TOKEN(VertexShader)
    FX_TOKEN(PixelShader)
    FX_TOKEN(GeometryShader)
    FX_TOKEN(DomainShader)
    FX_TOKEN(HullShader)
    FX_TOKEN(ComputeShader)
    FX_TOKEN(ZEnable)
    FX_TOKEN(ZWriteEnable)
    FX_TOKEN(CullMode)
    FX_TOKEN(SrcBlend)
    FX_TOKEN(DestBlend)
    FX_TOKEN(AlphaBlendEnable)
    FX_TOKEN(AlphaFunc)
    FX_TOKEN(AlphaRef)
    FX_TOKEN(ZFunc)
    FX_TOKEN(ColorWriteEnable)
    FX_TOKEN(IgnoreMaterialState)
  FX_END_TOKENS

  bool bRes = true;
  int n = pShTech->m_Passes.Num();
  pShTech->m_Passes.ReserveNew(n+1);
  SShaderPass *sm = &pShTech->m_Passes[n];
  sm->m_eCull = -1;
  sm->m_AlphaRef = ~0;

  SParserFrame VS, PS, GS, DS, HS, CS;
  FXMacroBin VSMacro, PSMacro, GSMacro, DSMacro, HSMacro, CSMacro;

  byte ZFunc = eCF_LEqual;

  byte ColorWriteMask = 0xff;

  byte AlphaFunc = eCF_Disable;
  byte AlphaRef = 0;
  int State = GS_DEPTHWRITE;

  int nMaxTMU = 0;
  signed char Cull = -1;
  int nIndex;
  EToken eSrcBlend = eT_unknown;
  EToken eDstBlend = eT_unknown;
  bool bBlend = false;

  while (Parser.ParseObject(sCommands, nIndex))
  {
    EToken eT = Parser.GetToken();
    switch (eT)
    {
      case eT_VertexShader:
        VS = Parser.m_Data;
        VSMacro = Parser.m_Macros[1];
        break;
      case eT_PixelShader:
        PS = Parser.m_Data;
        PSMacro = Parser.m_Macros[1];
        break;
      case eT_GeometryShader:
        GS = Parser.m_Data;
        GSMacro = Parser.m_Macros[1];
        break;
      case eT_DomainShader:
        DS = Parser.m_Data;
        DSMacro = Parser.m_Macros[1];
        break;
      case eT_HullShader:
        HS = Parser.m_Data;
        HSMacro = Parser.m_Macros[1];
        break;
      case eT_ComputeShader:
        CS = Parser.m_Data;
        CSMacro = Parser.m_Macros[1];
        break;

      case eT_ZEnable:
        if (Parser.GetBool(Parser.m_Data))
          State &= ~GS_NODEPTHTEST;
        else
          State |= GS_NODEPTHTEST;
        break;
      case eT_ZWriteEnable:
        if (Parser.GetBool(Parser.m_Data))
          State |= GS_DEPTHWRITE;
        else
          State &= ~GS_DEPTHWRITE;
        break;
      case eT_CullMode:
        eT = Parser.GetToken(Parser.m_Data);
        if (eT == eT_None)
          Cull = eCULL_None;
        else
        if (eT == eT_CCW || eT == eT_Back)
          Cull = eCULL_Back;
        else
        if (eT == eT_CW || eT == eT_Front)
          Cull = eCULL_Front;
        else
        {
          Warning("unknown CullMode parameter '%s' (Skipping)\n", Parser.GetString(eT));
          assert(0);
        }
        break;
      case eT_AlphaFunc:
        AlphaFunc = Parser.GetCompareFunc(Parser.GetToken(Parser.m_Data));
        break;
    case eT_ColorWriteEnable:
      {
        if (ColorWriteMask == 0xff)
          ColorWriteMask = 0;
        uint32 nCur = Parser.m_Data.m_nFirstToken;
        while (nCur <= Parser.m_Data.m_nLastToken)
        {
          uint32 nT = Parser.m_Tokens[nCur++];
          if (nT == eT_or)
            continue;
          if (nT == eT_0)
            ColorWriteMask |= 0;
          else
          if (nT == eT_RED)
            ColorWriteMask |= 1;
          else
          if (nT == eT_GREEN)
            ColorWriteMask |= 2;
          else
          if (nT == eT_BLUE)
            ColorWriteMask |= 4;
          else
          if (nT == eT_ALPHA)
            ColorWriteMask |= 8;
          else
          {
            Warning("unknown WriteMask parameter '%s' (Skipping)\n", Parser.GetString(eT));
          }
        }
      }
      break;
    case eT_ZFunc:
      ZFunc = Parser.GetCompareFunc(Parser.GetToken(Parser.m_Data));
      sm->m_PassFlags |= SHPF_FORCEZFUNC;
      break;
    case eT_AlphaRef:
      AlphaRef = Parser.GetInt(Parser.GetToken(Parser.m_Data));
      break;
    case eT_SrcBlend:
      eSrcBlend = Parser.GetToken(Parser.m_Data);
      break;
    case eT_DestBlend:
      eDstBlend = Parser.GetToken(Parser.m_Data);
      break;
    case eT_AlphaBlendEnable:
      bBlend = Parser.GetBool(Parser.m_Data);
      break;

    case eT_IgnoreMaterialState:
      sm->m_PassFlags |= SHPF_NOMATSTATE;
      break;

    default:
      assert(0);
    }
  }

  if (bBlend && eSrcBlend && eDstBlend)
  {
    int nSrc = Parser.GetSrcBlend(eSrcBlend);
    int nDst = Parser.GetDstBlend(eDstBlend);
    if (nSrc >= 0 && nDst >= 0)
    {
      State |= nSrc;
      State |= nDst;
    }
  }
  if (ColorWriteMask != 0xff)
  {
    for (int i=0; i<4; i++)
    {
      if (!(ColorWriteMask & (1<<i)))
        State |= GS_NOCOLMASK_R<<i;
    }
  }

  if (AlphaFunc)
  {
    switch (AlphaFunc)
    {
      case eCF_Greater:
        State |= GS_ALPHATEST_GREATER;
        break;
      case eCF_GEqual:
        State |= GS_ALPHATEST_GEQUAL;
        break;
      case eCF_Less:
        State |= GS_ALPHATEST_LESS;
        break;
      case eCF_LEqual:
        State |= GS_ALPHATEST_LEQUAL;
        break;
      default:
        assert(0);
    }
  }

  switch (ZFunc)
  {
    case eCF_Equal:
      State |= GS_DEPTHFUNC_EQUAL;
      break;
    case eCF_Greater:
      State |= GS_DEPTHFUNC_GREAT;
      break;
    case eCF_GEqual:
      State |= GS_DEPTHFUNC_GEQUAL;
      break;
    case eCF_Less:
      State |= GS_DEPTHFUNC_LESS;
      break;
    case eCF_NotEqual:
      State |= GS_DEPTHFUNC_NOTEQUAL;
      break;
    case eCF_LEqual:
      State |= GS_DEPTHFUNC_LEQUAL;
      break;
    default:
      assert(0);
  }

  sm->m_RenderState = State;
  sm->m_eCull = Cull;

  mfGeneratePublicFXParams(Parser.m_pCurShader, Parser);
  SShaderFXParams& FXParams = mfGetFXParams(Parser.m_pCurShader);

  if (!VS.IsEmpty())
    bRes &= ParseBinFX_Technique_Pass_LoadShader(Parser, VSMacro, VS, pShTech, sm, eHWSC_Vertex, FXParams);
  if (!PS.IsEmpty())
    bRes &= ParseBinFX_Technique_Pass_LoadShader(Parser, PSMacro, PS, pShTech, sm, eHWSC_Pixel, FXParams);
#if  !defined(PS3) && !defined(XENON) && !defined(CAFE)
  if (GEOMETRYSHADER_SUPPORT && (CParserBin::m_nPlatform==SF_D3D11 || CParserBin::m_nPlatform==SF_D3D10) && !GS.IsEmpty())
    bRes &= ParseBinFX_Technique_Pass_LoadShader(Parser, GSMacro, GS, pShTech, sm, eHWSC_Geometry, FXParams);
  if (CParserBin::m_nPlatform==SF_D3D11 && !HS.IsEmpty())
    bRes &= ParseBinFX_Technique_Pass_LoadShader(Parser, HSMacro, HS, pShTech, sm, eHWSC_Hull, FXParams);
  if (CParserBin::m_nPlatform==SF_D3D11 && !DS.IsEmpty())
    bRes &= ParseBinFX_Technique_Pass_LoadShader(Parser, DSMacro, DS, pShTech, sm, eHWSC_Domain, FXParams);
  if (CParserBin::m_nPlatform==SF_D3D11 && !CS.IsEmpty())
    bRes &= ParseBinFX_Technique_Pass_LoadShader(Parser, CSMacro, CS, pShTech, sm, eHWSC_Compute, FXParams);
#endif

  Parser.EndFrame(OldFrame);

  return bRes;
}

bool CShaderManBin::ParseBinFX_LightStyle_Val(CParserBin& Parser, SParserFrame& Frame, CLightStyle *ls)
{
  int i;
  char str[64];
  const char *pstr1, *pstr2;
	SLightStyleKeyFrame pKeyFrame;

  ls->m_Map.Free();
  string sr = Parser.GetString(Frame);
  const char *lstr = sr.c_str();

	// First count the keyframes
	size_t nKeyFrames = 0;
	while (true)
	{
		pstr1 = strchr(lstr, '|');
		if (!pstr1)
			break;
		pstr2 = strchr(pstr1+1, '|');
		if (!pstr2)
			break;
		if (pstr2-pstr1-1 > 0)
			++nKeyFrames;		
		lstr = pstr2;
	}
	ls->m_Map.reserve(nKeyFrames);

	lstr = sr.c_str();
  int n = 0;
  while (true)
  {
    pstr1 = strchr(lstr, '|');
    if (!pstr1)
      break;
    pstr2 = strchr(pstr1+1, '|');
    if (!pstr2)
      break;
    if (pstr2-pstr1-1 > 0)
    {
      strncpy(str, pstr1+1, pstr2-pstr1-1);
      str[pstr2-pstr1-1] = 0;
      i = sscanf(str, "%f %f %f %f %f %f %f", &pKeyFrame.cColor.r, &pKeyFrame.cColor.g, &pKeyFrame.cColor.b, &pKeyFrame.cColor.a,
																							&pKeyFrame.vPosOffset.x, &pKeyFrame.vPosOffset.y, &pKeyFrame.vPosOffset.z);
      switch (i)
      {
      case 1:
				{
					// Only luminance updates
					pKeyFrame.cColor.g = pKeyFrame.cColor.b = pKeyFrame.cColor.r;
					pKeyFrame.cColor.a = 1.0f;
					pKeyFrame.vPosOffset = Vec3(0);
				}
        break;

			case 3:
				{
					// No position/spec mult updates
					pKeyFrame.cColor.a = 1.0f;
					pKeyFrame.vPosOffset = Vec3(0);
				}
				break;

			case 4:
				{
					// No position
					pKeyFrame.vPosOffset = Vec3(0);
				}
				break;

			default:
				break;

      }
      ls->m_Map.AddElem(pKeyFrame);
      n++;
    }

    lstr = pstr2;
  }
  ls->m_Map.Shrink();
  assert(ls->m_Map.Num() == n);
  if (ls->m_Map.Num() == n)
    return true;
  return false;
}

bool CShaderManBin::ParseBinFX_LightStyle(CParserBin& Parser, SParserFrame& Frame, int nStyle)
{
  SParserFrame OldFrame = Parser.BeginFrame(Frame);

  FX_BEGIN_TOKENS
    FX_TOKEN(KeyFrameParams)
		FX_TOKEN(KeyFrameRandColor)
		FX_TOKEN(KeyFrameRandIntensity)
		FX_TOKEN(KeyFrameRandSpecMult)
		FX_TOKEN(KeyFrameRandPosOffset)
    FX_TOKEN(Speed)
  FX_END_TOKENS

  bool bRes = true;

  Parser.m_pCurShader->m_Flags |= EF_LIGHTSTYLE;
  if (CLightStyle::m_LStyles.Num() <= (uint32)nStyle)
    CLightStyle::m_LStyles.ReserveNew(nStyle+1);
  CLightStyle *ls = CLightStyle::m_LStyles[nStyle];
  if (!ls)
  {
    ls = new CLightStyle;
    ls->m_LastTime = 0;
    ls->m_Color = Col_White;
    CLightStyle::m_LStyles[nStyle] = ls;
  }
  ls->m_TimeIncr = 60;
  int nIndex;

  while (Parser.ParseObject(sCommands, nIndex))
  {
    EToken eT = Parser.GetToken();
    switch (eT)
    {
		case eT_KeyFrameRandColor:
			ls->m_bRandColor = Parser.GetBool(Parser.m_Data);
			break;

		case eT_KeyFrameRandIntensity:
			ls->m_bRandIntensity = Parser.GetBool(Parser.m_Data);
			break;

		case eT_KeyFrameRandSpecMult:
			ls->m_bRandSpecMult = Parser.GetBool(Parser.m_Data);
			break;

		case eT_KeyFrameRandPosOffset:
			ls->m_bRandPosOffset = Parser.GetBool(Parser.m_Data);
			break;

    case eT_KeyFrameParams:
      bRes &= ParseBinFX_LightStyle_Val(Parser, Parser.m_Data, ls);
      break;

    case eT_Speed:
      ls->m_TimeIncr = Parser.GetFloat(Parser.m_Data);
      break;
    default:
      assert(0);
    }
  }

	if( ls->m_Map.Num()&& (ls->m_bRandPosOffset || ls->m_bRandIntensity || ls->m_bRandSpecMult || ls->m_bRandColor ))
	{
		int32 nCount=ls->m_Map.Num();
		for(int f= 0; f < nCount; ++f)
		{
			SLightStyleKeyFrame &pKeyFrame = ls->m_Map[f];
			if( ls->m_bRandPosOffset )
				pKeyFrame.vPosOffset = Vec3(cry_frand()*2.0f-1.0f, cry_frand()*2.0f-1.0f, cry_frand()*2.0f-1.0f);

			if( ls->m_bRandColor )
				pKeyFrame.cColor *= ColorF(cry_frand(), cry_frand(), cry_frand(), 1.0f);

			if( ls->m_bRandIntensity )
				pKeyFrame.cColor *= cry_frand();

			if( ls->m_bRandSpecMult )
				pKeyFrame.cColor.a = cry_frand();
		}
	}

  Parser.EndFrame(OldFrame);

  return bRes;
}

bool CShaderManBin::ParseBinFX_Technique_Annotations_String(CParserBin& Parser, SParserFrame& Frame, SShaderTechnique *pShTech, std::vector<SShaderTechParseParams>& techParams, bool *bPublic)
{
  SParserFrame OldFrame = Parser.BeginFrame(Frame);

  FX_BEGIN_TOKENS
    FX_TOKEN(Public)
    FX_TOKEN(NoLights)
    FX_TOKEN(NoMaterialState)
    FX_TOKEN(PositionInvariant)
    FX_TOKEN(TechniqueZ)
    FX_TOKEN(TechniqueScatterPass)
    FX_TOKEN(TechniqueShadowPass)
    FX_TOKEN(TechniqueShadowGen)
    FX_TOKEN(TechniqueShadowGenDX11)
    FX_TOKEN(TechniqueCaustics)
    FX_TOKEN(TechniqueGlow)
    FX_TOKEN(TechniqueMotionBlur)
    FX_TOKEN(TechniqueCustomRender)
    FX_TOKEN(TechniqueRainPass)
    FX_TOKEN(TechniqueFurPass)
		FX_TOKEN(TechniqueEffectLayer)
    FX_TOKEN(TechniqueDebug)
		FX_TOKEN(TechniqueSoftAlphaTest)		
  FX_END_TOKENS

  bool bRes = true;
  int nIndex;

  while (Parser.ParseObject(sCommands, nIndex))
  {
    EToken eT = Parser.GetToken();
    switch (eT)
    {
      case eT_Public:
        if (pShTech)
          pShTech->m_Flags |= FHF_PUBLIC;
        else
        if (bPublic)
          *bPublic = true;
        break;

      case eT_PositionInvariant:
        if (pShTech)
          pShTech->m_Flags |= FHF_POSITION_INVARIANT;
        break;

      case eT_NoLights:
        if (pShTech)
          pShTech->m_Flags |= FHF_NOLIGHTS;
        break;

      case eT_NoMaterialState:
        if (Parser.m_pCurShader)
          Parser.m_pCurShader->m_Flags2 |= EF2_IGNORERESOURCESTATES;
        break;

      case eT_TechniqueZ:
        {
          if (!Parser.m_pCurShader)
            break;
          CCryNameR nameZ = Parser.GetNameString(Parser.m_Data);
          int idx = techParams.size()-1;
          assert(idx >= 0);
          techParams[idx].techName[TTYPE_Z] = nameZ;
        }
        break;
      case eT_TechniqueScatterPass:
        {
          if (!Parser.m_pCurShader)
            break;
          CCryNameR nameScatterPass = Parser.GetNameString(Parser.m_Data);
          int idx = techParams.size()-1;
          assert(idx >= 0);
          techParams[idx].techName[TTYPE_SCATTERPASS] = nameScatterPass;
        }
        break;
      case eT_TechniqueShadowGen:
        {
          if (!Parser.m_pCurShader)
            break;
          CCryNameR nameGenShadow = Parser.GetNameString(Parser.m_Data);
          int idx = techParams.size()-1;
          assert(idx >= 0);
          techParams[idx].techName[TTYPE_SHADOWGEN] = nameGenShadow;
        }
        break;
      case eT_TechniqueShadowGenDX11:
        {
#if !defined(XENON) && !defined(PS3)
          if (!Parser.m_pCurShader)
            break;
          CCryNameR nameGenShadow = Parser.GetNameString(Parser.m_Data);
          int idx = techParams.size()-1;
          assert(idx >= 0);
          techParams[idx].techName[TTYPE_SHADOWGENGS] = nameGenShadow;
#endif
        }
        break;
      case eT_TechniqueShadowPass:
        {
          if (!Parser.m_pCurShader)
            break;
          CCryNameR nameShadow = Parser.GetNameString(Parser.m_Data);
          int idx = techParams.size()-1;
          assert(idx >= 0);
          techParams[idx].techName[TTYPE_SHADOWPASS] = nameShadow;
        }
        break;
      case eT_TechniqueCaustics:
        {
          if (!Parser.m_pCurShader)
            break;
          CCryNameR name = Parser.GetNameString(Parser.m_Data);
          int idx = techParams.size()-1;
          assert(idx >= 0);
          techParams[idx].techName[TTYPE_CAUSTICS] = name;
        }
        break;
      case eT_TechniqueGlow:
        {
          if (!Parser.m_pCurShader)
            break;
          CCryNameR nameGlow = Parser.GetNameString(Parser.m_Data);
          int idx = techParams.size()-1;
          assert(idx >= 0);
          techParams[idx].techName[TTYPE_GLOWPASS] = nameGlow;
        }
        break;
      case eT_TechniqueMotionBlur:
        {
          if (!Parser.m_pCurShader)
            break;
          CCryNameR nameMotionBlur = Parser.GetNameString(Parser.m_Data);
          int idx = techParams.size()-1;
          assert(idx >= 0);
          techParams[idx].techName[TTYPE_MOTIONBLURPASS] = nameMotionBlur;
        }
        break;
      case eT_TechniqueCustomRender:
        {
          if (!Parser.m_pCurShader)
            break;
          CCryNameR nameTech = Parser.GetNameString(Parser.m_Data);
          int idx = techParams.size()-1;
          assert(idx >= 0);
          techParams[idx].techName[TTYPE_CUSTOMRENDERPASS] = nameTech;
        }
        break;
      case eT_TechniqueFurPass:
        {
          if (!Parser.m_pCurShader)
            break;
          CCryNameR nameTech = Parser.GetNameString(Parser.m_Data);
          int idx = techParams.size()-1;
          assert(idx >= 0);
          techParams[idx].techName[TTYPE_FURPASS] = nameTech;
        }
        break;
			case eT_TechniqueEffectLayer:
				{
					if (!Parser.m_pCurShader)
						break;
					CCryNameR nameTech = Parser.GetNameString(Parser.m_Data);
					int idx = techParams.size()-1;
					assert(idx >= 0);
					techParams[idx].techName[TTYPE_EFFECTLAYER] = nameTech;
				}
				break;
      case eT_TechniqueDebug:
        {
#if !defined(XENON) && !defined(PS3)
          if (!Parser.m_pCurShader)
            break;
          CCryNameR nameDebug = Parser.GetNameString(Parser.m_Data);
          int idx = techParams.size()-1;
          assert(idx >= 0);
          techParams[idx].techName[TTYPE_DEBUG] = nameDebug;
#endif
        }
        break;
			case eT_TechniqueSoftAlphaTest:
				{
					if (!Parser.m_pCurShader)
						break;
					CCryNameR nameTech = Parser.GetNameString(Parser.m_Data);
					int idx = techParams.size()-1;
					assert(idx >= 0);
					techParams[idx].techName[TTYPE_SOFTALPHATESTPASS] = nameTech;
				}
				break;
      default:
        assert(0);
    }
  }

  Parser.EndFrame(OldFrame);

  return bRes;
}

bool CShaderManBin::ParseBinFX_Technique_Annotations(CParserBin& Parser, SParserFrame& Frame, SShaderTechnique *pShTech, std::vector<SShaderTechParseParams>& techParams, bool *bPublic)
{
  SParserFrame OldFrame = Parser.BeginFrame(Frame);

  FX_BEGIN_TOKENS
    FX_TOKEN(string)
  FX_END_TOKENS

  bool bRes = true;
  int nIndex;

  while (Parser.ParseObject(sCommands, nIndex))
  {
    EToken eT = Parser.GetToken();
    switch (eT)
    {
    case eT_string:
      {
        eT = Parser.GetToken(Parser.m_Name);
        assert(eT == eT_Script);
        bRes &= ParseBinFX_Technique_Annotations_String(Parser, Parser.m_Data, pShTech, techParams, bPublic);
      }
      break;

    default:
      assert(0);
    }
  }

  Parser.EndFrame(OldFrame);

  return bRes;
}

bool CShaderManBin::ParseBinFX_Technique_CustomRE(CParserBin& Parser, SParserFrame& Frame, SParserFrame& Name, SShaderTechnique *pShTech)
{
  uint32 nName = Parser.GetToken(Name);

  if (nName == eT_Flare)
  {
    CREFlare *ps = new CREFlare;
    if (ps->mfCompile(Parser, Frame))
    {
      pShTech->m_REs.AddElem(ps);
      pShTech->m_Flags |= FHF_RE_FLARE;
      return true;
    }
    else
      delete ps;
  }
  else
  if (nName == eT_Cloud)
  {
    CRECloud *ps = new CRECloud;
    if (ps->mfCompile(Parser, Frame))
    {
      pShTech->m_REs.AddElem(ps);
      pShTech->m_Flags |= FHF_RE_CLOUD;
      return true;
    }
    else
      delete ps;
  }
  else
  if (nName == eT_Beam)
  {
    CREBeam *ps = new CREBeam;
    if (ps->mfCompile(Parser, Frame))
    {
      pShTech->m_REs.AddElem(ps);
    }
    else
      delete ps;
  }
  else
  if (nName == eT_Ocean)
  {
    assert(0);
  }

  return true;
}

SShaderTechnique *CShaderManBin::ParseBinFX_Technique(CParserBin& Parser, SParserFrame& Frame, SParserFrame Annotations, std::vector<SShaderTechParseParams>& techParams, bool *bPublic)
{
	LOADING_TIME_PROFILE_SECTION(iSystem);

  SParserFrame OldFrame = Parser.BeginFrame(Frame);

  FX_BEGIN_TOKENS
    FX_TOKEN(pass)
    FX_TOKEN(CustomRE)
    FX_TOKEN(Style)
  FX_END_TOKENS

  bool bRes = true;
  SShaderTechnique *pShTech = NULL;
  if (Parser.m_pCurShader)
    pShTech = new SShaderTechnique;

  if (Parser.m_pCurShader)
  {
    SShaderTechParseParams ps;
    techParams.push_back(ps);
  }

  if (!Annotations.IsEmpty())
    ParseBinFX_Technique_Annotations(Parser, Annotations, pShTech, techParams, bPublic);

  while (Parser.ParseObject(sCommands))
  {
    EToken eT = Parser.GetToken();
    switch (eT)
    {
      case eT_pass:
        if (pShTech)
          bRes &= ParseBinFX_Technique_Pass(Parser, Parser.m_Data, pShTech);
        break;

      case eT_Style:
        if (pShTech)
          ParseBinFX_LightStyle(Parser, Parser.m_Data, Parser.GetInt(Parser.GetToken(Parser.m_Name)));
        break;

      case eT_CustomRE:
        if (pShTech)
          bRes &= ParseBinFX_Technique_CustomRE(Parser, Parser.m_Data, Parser.m_Name, pShTech);
        break;

      default:
        assert(0);
    }
  }

  if (bRes)
  {
    if (Parser.m_pCurShader && pShTech)
    {
      Parser.m_pCurShader->m_HWTechniques.AddElem(pShTech);
    }
  }
  else
  {
    techParams.pop_back();
  }

  Parser.EndFrame(OldFrame);

  return pShTech;
}

float g_fTimeA;

bool CShaderManBin::ParseBinFX(SShaderBin *pBin, CShader *ef, uint64 nMaskGen)
{
	LOADING_TIME_PROFILE_SECTION(iSystem);

  bool bRes = true;

  float fTimeA = iTimer->GetAsyncCurTime();

#if !defined(SHADER_NO_SOURCES)
  CParserBin Parser(pBin, ef);

  CShader *efGen = ef->m_pGenShader;

  if (efGen && efGen->m_ShaderGenParams)
    AddGenMacroses(efGen->m_ShaderGenParams, Parser, nMaskGen);

  pBin->Lock();
  Parser.Preprocess(0, pBin->m_Tokens, &pBin->m_TokenTable);
  ef->m_CRC32 = pBin->m_CRC32;
  ef->m_SourceCRC32 = pBin->m_SourceCRC32;
  pBin->Unlock();
#endif

#if defined(SHADER_NO_SOURCES)
  iLog->Log("ERROR: Couldn't find binary shader '%s' (0x%x)", ef->GetName(), ef->m_nMaskGenFX);
  return false;
#else
	SParserFrame Frame(0, (Parser.m_Tokens.size() > 0 ? Parser.m_Tokens.size()-1 : 0));
  Parser.BeginFrame(Frame);

  FX_BEGIN_TOKENS
    FX_TOKEN(static)
    FX_TOKEN(half)
    FX_TOKEN(half2)
    FX_TOKEN(half3)
    FX_TOKEN(half4)
    FX_TOKEN(half2x4)
    FX_TOKEN(half3x4)
    FX_TOKEN(half4x4)
    FX_TOKEN(float)
    FX_TOKEN(float2)
    FX_TOKEN(float3)
    FX_TOKEN(float4)
    FX_TOKEN(float2x4)
    FX_TOKEN(float3x4)
    FX_TOKEN(float4x4)
    FX_TOKEN(bool)
    FX_TOKEN(int)
    FX_TOKEN(struct)
    FX_TOKEN(sampler1D)
    FX_TOKEN(sampler2D)
    FX_TOKEN(sampler3D)
    FX_TOKEN(samplerCUBE)
    FX_TOKEN(Texture2D)
    FX_TOKEN(Texture2DArray)
    FX_TOKEN(Texture2DMS)
    FX_TOKEN(technique)
    FX_TOKEN(SamplerState)
    FX_TOKEN(SamplerComparisonState)
    FX_TOKEN(Buffer)
    FX_TOKEN(StructuredBuffer)
    FX_TOKEN(RWStructuredBuffer)
    FX_TOKEN(ByteAddressBuffer)
    FX_TOKEN(RWByteAddressBuffer)
  FX_END_TOKENS

  std::vector<SShaderTechParseParams> techParams;
  CCryNameR techStart[2];

	// From MemReplay analysis of shader params, 200 should be more than enough space
	s_tempFXParams.reserve(200);
	s_tempFXParams.clear();

	SShaderFXParams& FXP = mfGetFXParams(Parser.m_pCurShader);
	FXP.m_FXParams.swap(s_tempFXParams);

	ef->mfFree();

  assert (ef->m_HWTechniques.Num() == 0);
  int nInd = 0;

  while (Parser.ParseObject(sCommands))
  {
    EToken eT = Parser.GetToken();
    SCodeFragment Fr;
    SFXParam P;
    string szR;
    switch (eT)
    {
      case eT_struct:
      case eT_SamplerState:
      case eT_SamplerComparisonState:
        Fr.m_nFirstToken = Parser.FirstToken();
				Fr.m_nLastToken = Parser.m_CurFrame.m_nCurToken-1;
        Fr.m_dwName = Parser.m_Tokens[Fr.m_nFirstToken+1];
#ifdef _DEBUG
        //Fr.m_Name = Parser.GetString(Fr.m_dwName);
#endif
        Fr.m_eType = eFT_Structure;
        Parser.m_CodeFragments.push_back(Fr);
        break;

      case eT_int:
      case eT_bool:
      case eT_half:
      case eT_half2:
      case eT_half3:
      case eT_half4:
      case eT_half2x4:
      case eT_half3x4:
      case eT_half4x4:
      case eT_float:
      case eT_float2:
      case eT_float3:
      case eT_float4:
      case eT_float2x4:
      case eT_float3x4:
      case eT_float4x4:
        {
          SFXParam Pr;
          Parser.CopyTokens(Parser.m_Name, Pr.m_dwName);
          if (eT == eT_float2x4 || eT == eT_half2x4)
            Pr.m_nParameters = 2;
          else
          if (eT == eT_float3x4 || eT == eT_half3x4)
            Pr.m_nParameters = 3;
          else
          if (eT == eT_float4x4 || eT == eT_half4x4)
            Pr.m_nParameters = 4;
          else
            Pr.m_nParameters = 1;

          if (eT == eT_float || eT == eT_half || eT == eT_int || eT == eT_bool)
            Pr.m_nComps = 1;
          else
          if (eT == eT_float2 || eT == eT_half2)
            Pr.m_nComps = 2;
          else
          if (eT == eT_float3 || eT == eT_half3)
            Pr.m_nComps = 3;
          else
          if (eT == eT_float4 || eT == eT_float2x4 || eT == eT_float3x4 || eT == eT_float4x4 ||
              eT == eT_half4 || eT == eT_half2x4 || eT == eT_half3x4 || eT == eT_half4x4)
            Pr.m_nComps = 4;

          if (eT == eT_int)
            Pr.m_eType = eType_INT;
          else
          if (eT == eT_bool)
            Pr.m_eType = eType_BOOL;
          else
          if (eT >= eT_half && eT <= eT_half3x3)
            Pr.m_eType = eType_HALF;
          else
            Pr.m_eType = eType_FLOAT;

          if (!Parser.m_Assign.IsEmpty() && Parser.GetToken(Parser.m_Assign) == eT_STANDARDSGLOBAL)
          {
            ParseBinFX_Global(Parser, Parser.m_Annotations, NULL, techStart);
          }
          else
          {
            uint32 nTokAssign = 0;
            if (Parser.m_Assign.IsEmpty() && !Parser.m_Value.IsEmpty())
            {
              nTokAssign = Parser.m_Tokens[Parser.m_Value.m_nFirstToken];
              if (nTokAssign == eT_br_cv_1)
                nTokAssign = Parser.m_Tokens[Parser.m_Value.m_nFirstToken+1];
            }
            else
            if (!Parser.m_Assign.IsEmpty())
              nTokAssign = Parser.m_Tokens[Parser.m_Assign.m_nFirstToken];
            if (nTokAssign)
            {
              const char *assign = Parser.GetString(nTokAssign);
              if (!strnicmp(assign, "SK_", 3))
                Pr.m_nCB = CB_SKIN_DATA;
              else
              if (!strnicmp(assign, "SH_", 3))
                Pr.m_nCB = CB_SHAPE_DATA;
              else
              if (!assign[0] || !strnicmp(assign, "PB_", 3))
                Pr.m_nCB = CB_PER_BATCH;
              else
              if (!assign[0] || !strnicmp(assign, "SG_", 3))
                Pr.m_nCB = CB_PER_SHADOWGEN;
              else
              if (!strnicmp(assign, "PI_", 3))
                Pr.m_nCB = CB_PER_INSTANCE;
              else
              if (!strnicmp(assign, "SI_", 3))
              {
#if defined (DIRECT3D10) || defined(PS3)
                Pr.m_nCB = CB_STATIC_INSTANCE;
#else
                Pr.m_nCB = CB_PER_INSTANCE;
#endif
              }
              else
              if (!strnicmp(assign, "PF_", 3))
                Pr.m_nCB = CB_PER_FRAME;
              else
              if (!strnicmp(assign, "PM_", 3))
              {
                Pr.m_nCB = CB_PER_MATERIAL;
              }
              else
              if (!strnicmp(assign, "PL_", 3))
                Pr.m_nCB = CB_PER_LIGHT;
              else
              if (!strnicmp(assign, "register", 8))
                Pr.m_nCB = CB_PER_BATCH;
              else
                Pr.m_nCB = CB_PER_BATCH;
            }
            else
            if (CParserBin::m_nPlatform & (SF_D3D11 | SF_D3D10 | SF_PS3 | SF_CAFE))
            {
              uint32 nTokName = Parser.GetToken(Parser.m_Name);
              if (nTokName == eT__g_SkinQuat)
                Pr.m_nCB = CB_SKIN_DATA;
              else
              if (nTokName == eT__g_ShapeDeformationData)
                Pr.m_nCB = CB_SHAPE_DATA;
              else
              {
                const char *name = Parser.GetString(nTokName);
                if (!strncmp(name, "PI_", 3))
                  Pr.m_nCB = CB_PER_INSTANCE;
                else  
                  Pr.m_nCB = CB_PER_BATCH;
              }
            }

            Pr.PostLoad(Parser, Parser.m_Name, Parser.m_Annotations, Parser.m_Value, Parser.m_Assign);

            EParamType eType;
            string szReg = Pr.GetValueForName("register", eType);
            if (!szReg.empty())
            {
              assert(szReg[0] == 'c');
              Pr.m_nRegister[eHWSC_Vertex] = atoi(&szReg[1]);
              Pr.m_nRegister[eHWSC_Pixel] = Pr.m_nRegister[eHWSC_Vertex];
#if !defined(PS3) && !defined(XENON) && !defined(CAFE)
              if (GEOMETRYSHADER_SUPPORT && (CParserBin::m_nPlatform==SF_D3D11 || CParserBin::m_nPlatform==SF_D3D10))
                Pr.m_nRegister[eHWSC_Geometry] = Pr.m_nRegister[eHWSC_Vertex];
              if (CParserBin::m_nPlatform==SF_D3D11)
                Pr.m_nRegister[eHWSC_Domain] = Pr.m_nRegister[eHWSC_Vertex];
#endif
            }
            uint32 prFlags = Pr.GetParamFlags();
            if (prFlags & PF_TWEAKABLE_MASK)
            {
              if (!(prFlags & PF_ALWAYS))
              {
                Pr.m_nCB = CB_PER_MATERIAL;
                assert(prFlags & PF_CUSTOM_BINDED);
              }
            }
            mfAddFXParam(Parser.m_pCurShader, &Pr);
          }
        }
        break;

      case eT_Texture2D:
      case eT_Texture2DMS:
      case eT_Texture2DArray:
      case eT_sampler1D:
      case eT_sampler2D:
      case eT_sampler3D:
      case eT_samplerCUBE:
        {
          Fr.m_nFirstToken = Parser.FirstToken();
          uint32 nTokenOffset = (eT != eT_Texture2DMS)? 1 : 4; // Texture2DMS is particular case, skip Texture2DMS<type> tokens
          Fr.m_nLastToken = Fr.m_nFirstToken + nTokenOffset;
          if (!Parser.m_Assign.IsEmpty())
            Fr.m_nLastToken = Parser.m_Assign.m_nLastToken;
          Fr.m_dwName = Parser.m_Tokens[Fr.m_nFirstToken + nTokenOffset];
          Fr.m_eType = eFT_Sampler;
          Parser.m_CodeFragments.push_back(Fr);

          //// handy for debugging - do not remove plz
          //const char *pszToken0 = Parser.GetString( Parser.m_Tokens[Fr.m_nFirstToken]  );
          //const char *pszToken1 = Parser.GetString( Parser.m_Tokens[Fr.m_nFirstToken+1] );
          //const char *pszToken2 = Parser.GetString( Parser.m_Tokens[Fr.m_nFirstToken+2] );

          bRes &= ParseBinFX_Sampler(Parser, Parser.m_Data, Fr.m_dwName, Parser.m_Annotations);
        }
        break;

      case eT_Buffer:
      case eT_StructuredBuffer:
      case eT_RWStructuredBuffer:
      case eT_ByteAddressBuffer:
      case eT_RWByteAddressBuffer:
        {
          Fr.m_nFirstToken = Parser.FirstToken();
          Fr.m_nLastToken = Fr.m_nFirstToken+1;
          if (!Parser.m_Assign.IsEmpty())
            Fr.m_nLastToken = Parser.m_Assign.m_nLastToken+1;
          Fr.m_dwName = Parser.m_Tokens[Parser.m_Name.m_nFirstToken];
          Fr.m_eType = eFT_Structure;
          Parser.m_CodeFragments.push_back(Fr);
        }
        break;

      case eT_technique:
        {
          uint32 nToken = Parser.m_Tokens[Parser.m_Name.m_nFirstToken];
          const char *szName = Parser.GetString(nToken);
          SShaderTechnique *pShTech = ParseBinFX_Technique(Parser, Parser.m_Data, Parser.m_Annotations, techParams, NULL);
          if (szName)
          {
            pShTech->m_NameStr = szName;
            pShTech->m_NameCRC = szName;
          }
        }
        break;

      default:
        //assert(0);
				break;
    }
  }

	FXP.m_FXParams.swap(s_tempFXParams);
	FXP.m_FXParams.reserve(FXP.m_FXParams.size() + s_tempFXParams.size());
	FXP.m_FXParams.insert(FXP.m_FXParams.end(), s_tempFXParams.begin(), s_tempFXParams.end());	

  m_pCEF->mfPostLoadFX(ef, techParams, techStart);

  g_fTimeA += iTimer->GetAsyncCurTime() - fTimeA;

  return bRes;
#endif
}

bool CShaderManBin::ParseBinFX_Dummy(SShaderBin *pBin, std::vector<string>& ShaderNames, const char *szName)
{
	bool bRes = true;
	CParserBin Parser(pBin, NULL);

	pBin->Lock();
	Parser.Preprocess(0, pBin->m_Tokens, &pBin->m_TokenTable);
	pBin->Unlock();

	SParserFrame Frame(0, Parser.m_Tokens.size()-1);
	Parser.BeginFrame(Frame);

	FX_BEGIN_TOKENS
		FX_TOKEN(static)
		FX_TOKEN(half)
		FX_TOKEN(half2)
		FX_TOKEN(half3)
		FX_TOKEN(half4)
		FX_TOKEN(half2x4)
		FX_TOKEN(half3x4)
		FX_TOKEN(half4x4)
		FX_TOKEN(float)
		FX_TOKEN(float2)
		FX_TOKEN(float3)
		FX_TOKEN(float4)
		FX_TOKEN(float2x4)
		FX_TOKEN(float3x4)
		FX_TOKEN(float4x4)
		FX_TOKEN(bool)
		FX_TOKEN(int)
		FX_TOKEN(Buffer)
		FX_TOKEN(StructuredBuffer)
		FX_TOKEN(RWStructuredBuffer)
		FX_TOKEN(struct)
		FX_TOKEN(sampler1D)
		FX_TOKEN(sampler2D)
		FX_TOKEN(sampler3D)
		FX_TOKEN(samplerCUBE)
		FX_TOKEN(technique)
		FX_TOKEN(SamplerState)
		FX_TOKEN(SamplerComparisonState)
		FX_TOKEN(Texture2D)
		FX_TOKEN(Texture2DArray)
		FX_TOKEN(Texture2DMS)
	FX_END_TOKENS

	std::vector<SShaderTechParseParams> techParams;
	CCryNameR techStart[2];
	bool bPublic = false;
	std::vector<string> PubTechniques;

	while (Parser.ParseObject(sCommands))
	{
		EToken eT = Parser.GetToken();
		SCodeFragment Fr;
		switch (eT)
		{
		case eT_half:
		case eT_float:
			if (!Parser.m_Assign.IsEmpty() && Parser.GetToken(Parser.m_Assign) == eT_STANDARDSGLOBAL)
			{
				ParseBinFX_Global(Parser, Parser.m_Annotations, &bPublic, techStart);
			}
			break;
		case eT_Buffer:
		case eT_StructuredBuffer:
		case eT_RWStructuredBuffer:
		case eT_struct:
		case eT_SamplerState:
		case eT_SamplerComparisonState:
		case eT_int:
		case eT_bool:

		case eT_half2:
		case eT_half3:
		case eT_half4:
		case eT_half2x4:
		case eT_half3x4:
		case eT_half4x4:

		case eT_float2:
		case eT_float3:
		case eT_float4:
		case eT_float2x4:
		case eT_float3x4:
		case eT_float4x4:

		case eT_Texture2D:
		case eT_Texture2DMS:
		case eT_Texture2DArray:
		case eT_sampler1D:
		case eT_sampler2D:
		case eT_sampler3D:
		case eT_samplerCUBE:
			break;

		case eT_technique:
			{
				uint32 nToken = Parser.m_Tokens[Parser.m_Name.m_nFirstToken];
				bool bPublicTechnique = false;
				SShaderTechnique *pShTech = ParseBinFX_Technique(Parser, Parser.m_Data, Parser.m_Annotations, techParams, &bPublicTechnique);
				if (bPublicTechnique)
				{
					const char *name = Parser.GetString(nToken);
					PubTechniques.push_back(name);
				}
			}
			break;

		default:
			assert(0);
		}
	}

	if (bPublic)
		ShaderNames.push_back(szName);
	if (PubTechniques.size())
	{
		uint32 i;
		for (i=0; i<PubTechniques.size(); i++)
		{
			string str = szName;
			str += ".";
			str += PubTechniques[i];
			ShaderNames.push_back(str);
		}
	}

	return bRes;
}

inline bool CompareInstParams(const SCGParam&a, const SCGParam &b)
{
  return (a.m_dwBind < b.m_dwBind);
}

void CShaderMan::mfPostLoadFX(CShader *ef, std::vector<SShaderTechParseParams>& techParams, CCryNameR techStart[2])
{
  ef->m_HWTechniques.Shrink();

  uint32 i;

  assert(techParams.size() == ef->m_HWTechniques.Num());
  for (i=0; i<ef->m_HWTechniques.Num(); i++)
  {
    SShaderTechnique *hw = ef->m_HWTechniques[i];
    SShaderTechParseParams *ps = &techParams[i];
    uint32 n;
    for (n=0; n<TTYPE_MAX; n++)
    {
      if (ps->techName[n].c_str()[0])
      {
        if (hw->m_NameStr == ps->techName[n])
          iLog->LogWarning("WARNING: technique '%s' refers to itself as the next technique (ignored)", hw->m_NameStr.c_str());
        else
        {
          uint32 j;
          for (j=0; j<ef->m_HWTechniques.Num(); j++)
          {
            SShaderTechnique *hw2 = ef->m_HWTechniques[j];
            if (hw2->m_NameStr == ps->techName[n])
            {
              hw->m_nTechnique[n] = j;
              break;
            }
          }
          if (j == ef->m_HWTechniques.Num())
            iLog->LogWarning("WARNING: couldn't find technique '%s' in the sequence for technique '%s' (ignored)", ps->techName[n].c_str(), hw->m_NameStr.c_str());
        }
      }
    }
    if (hw->m_nTechnique[TTYPE_Z] >= 0)
    {
      SShaderTechnique *hw2 = ef->m_HWTechniques[hw->m_nTechnique[TTYPE_Z]];
      if (hw2->m_Passes.Num())
      {
        SShaderPass *pass = &hw2->m_Passes[0];
        if (pass->m_RenderState & GS_DEPTHWRITE)
          hw->m_Flags |= FHF_WASZWRITE;
      }
    }
    bool bTransparent = true;
    for (uint32 j=0; j<hw->m_Passes.Num(); j++)
    {
      SShaderPass *pass = &hw->m_Passes[j];
#if !defined (PS3) && !defined (XENON) && !defined(CAFE)
      if ((CParserBin::m_nPlatform==SF_D3D11 || CParserBin::m_nPlatform==SF_D3D10) && pass->m_GShader)
        hw->m_Flags |= FHF_USE_GEOMETRY_SHADER;
      if (CParserBin::m_nPlatform==SF_D3D11 && pass->m_HShader)
        hw->m_Flags |= FHF_USE_HULL_SHADER;
      if (CParserBin::m_nPlatform==SF_D3D11 && pass->m_DShader)
        hw->m_Flags |= FHF_USE_DOMAIN_SHADER;
#endif
      if (!(pass->m_RenderState & GS_BLEND_MASK))
        bTransparent = false;
    }
    if (bTransparent)
      hw->m_Flags |= FHF_TRANSPARENT;
  }
}

//===========================================================================================

void STexSamplerRT::Update()
{
  if (m_pAnimInfo && m_pAnimInfo->m_Time && gRenDev->m_bPauseTimer==0)
  {
    assert(gRenDev->m_RP.m_TI[gRenDev->m_RP.m_nProcessThreadID].m_RealTime>=0);
    uint32 m = (uint32)(gRenDev->m_RP.m_TI[gRenDev->m_RP.m_nProcessThreadID].m_RealTime / m_pAnimInfo->m_Time) % (m_pAnimInfo->m_NumAnimTexs);
    assert(m<(uint32)m_pAnimInfo->m_TexPics.Num()); 

		if(m_pTex)
		{
			m_pTex->Release();
		}

    m_pTex = m_pAnimInfo->m_TexPics[m];

		m_pTex->AddRef();
  }
}

string SFXParam::GetCompName(uint32 nId)
{
	if (nId < 0 || nId > 3)
		return "";
	char nm[16];




	uint32 offset = 3;
	sprintf(nm, "__%d", nId);

	const char *s = strstr(m_Name.c_str(), nm);
	if (!s)
		return "";
	s += offset;
	int n = 0;
	char ss[128];
	while (s[n])
	{
		if (s[n] <= 0x20)
			break;



		if (s[n] == '_' && s[n+1] == '_')

			break;
		ss[n] = s[n];
		n++;
	}
	ss[n] = 0;

	return ss;
}

string SFXParam::GetParamComp(uint32 nOffset)
{
  const char *szValue = m_Values.c_str();
  if (!szValue[0])
    return "";
  if (szValue[0] == '{')
    szValue++;
  uint32 n = 0;
  while (n != nOffset)
  {
    while (szValue[0] != ',' && szValue[0] != ';' && szValue[0] != '}' && szValue[0] != 0) {szValue++;}
    if (szValue[0] == ';' || szValue[0] == '}' || szValue[0] == 0)
      return "";
    szValue++;
    n++;
  }
  while (*szValue == ' ' || *szValue == 8) {szValue++;}
  n = 0;
  while (szValue[n] != ',' && szValue[n] != ';' && szValue[n] != '}' && szValue[n] != 0) {n++;}
  string retStr(szValue, n); 

  return retStr;
}

uint32 SFXParam::GetComponent(EHWShaderClass eSHClass)
{
  char *src = (char *)m_Annotations.c_str();
  char annot[256];
  int nComp = 0;
  fxFill(&src, annot);
  if (!strncmp(&annot[1], "sregister", 9)) 
  {
    if ((eSHClass == eHWSC_Pixel && annot[0] =='v') || (eSHClass == eHWSC_Vertex && annot[0] =='p'))
    {
      fxFill(&src, annot);
      if (strncmp(&annot[1], "sregister", 9)) 
        return 0;
      if ((eSHClass == eHWSC_Pixel && annot[0] =='v') || (eSHClass == eHWSC_Vertex && annot[0] =='p'))
        return 0;
    }
    char *b = &annot[10];
    SkipCharacters (&b, kWhiteSpace);
    assert(b[0] == '=');
    b++;
    SkipCharacters (&b, kWhiteSpace);
    assert(b[0] == 'c');
    if (b[0] == 'c')
    {
      int nReg = atoi(&b[1]);
      b++;
      while (*b != '.')
      {
        if (*b == 0) // Vector without swizzling
          break;
        b++;
      }
      if (*b == '.')
      {
        b++;
        switch(b[0])
        {
        case 'x':
        case 'r': nComp = 0; break;
        case 'y':
        case 'g': nComp = 1; break;
        case 'z':
        case 'b': nComp = 2; break;
        case 'w':
        case 'a': nComp = 3; break;
        default:
          assert(0);
        }
      }
    }
  }
  return nComp;
}

string SFXParam::GetValueForName(const char *szName, EParamType& eType)
{
  eType = eType_UNKNOWN;
  if (m_Annotations.empty())
    return "";

  char buf[256];
  char tok[128];
  char *szA = (char *)m_Annotations.c_str();
  SkipCharacters(&szA, kWhiteSpace);
  while (true)
  {
    if (!fxFill(&szA, buf))
      break;
    char *b = buf;
    fxFillPr(&b, tok);
    eType = eType_UNKNOWN;
    if (!stricmp(tok, "string"))
      eType = eType_STRING;
    else
    if (!stricmp(tok, "float"))
      eType = eType_FLOAT;
    else
      if (!stricmp(tok, "half"))
        eType = eType_HALF;

    if (eType != eType_UNKNOWN)
    {
      if (!fxFillPr(&b, tok))
        continue;
      if (stricmp(tok, szName))
        continue;
      SkipCharacters(&b, kWhiteSpace);
      if (b[0] == '=')
      {
        b++;
        if (!fxFillPrC(&b, tok))
          break;
      }
      return tok;
    }
    else
    {
      if (stricmp(tok, szName))
        continue;
      eType = eType_STRING;
      if (!fxFillPr(&b, tok))
        continue;
      if (tok[0] == '=')
      {
        if (!fxFillPr(&b, tok))
          break;
      }
      return tok;
    }
  }

  return "";
}

const char *CShaderMan::mfParseFX_Parameter (const string& script, EParamType eType, const char *szName)
{
  static char sRet[128];
  int nLen = script.length();
  char *pTemp = new char [nLen+1];
  strcpy(pTemp, script.c_str());
  sRet[0] = 0;
  char *buf = pTemp;

  char* name;
  long cmd;
  char *data;

  enum {eString = 1};

  static STokenDesc commands[] =
  {
    {eString, "String"},

    {0,0}
  };

  while ((cmd = shGetObject (&buf, commands, &name, &data)) > 0)
  {
    switch (cmd)
    {
    case eString:
      {
        if (eType != eType_STRING)
          break;
        char *szScr = data;
        if (*szScr == '"')
          szScr++;
        int n = 0;
        while(szScr[n] != 0)
        {
          if (szScr[n] == '"')
            szScr[n] = ' ';
          n++;
        }
        if (!stricmp(szName, name))
        {
          strcpy(sRet, data);
          break;
        }
      }
      break;
    }
  }

  SAFE_DELETE_ARRAY(pTemp);

  if (sRet[0])
    return sRet;
  else
    return NULL;
}

SFXParam *CShaderMan::mfGetFXParameter(std::vector<SFXParam>& Params, const char *param)
{
  uint32 j;
  for (j=0; j<Params.size(); j++)
  {
    SFXParam *pr = &Params[j];
    char nameParam[256];
    int n = 0;
    const char *szSrc = pr->m_Name.c_str();
    int nParams = 1;
    while (*szSrc != 0)
    {
      if (*szSrc == '[')
      {
        nParams = atoi(&szSrc[1]);
        break;
      }
      nameParam[n++] = *szSrc;
      szSrc++;
    }
    nameParam[n] = 0;
    if (!stricmp(nameParam, param))
      return pr;
  }
  return NULL;
}

// We have to parse part of the shader to enumerate public techniques
bool CShaderMan::mfAddFXShaderNames(const char *szName, std::vector<string>* ShaderNames, bool bUpdateCRC)
{
  bool bRes = true;
  SShaderBin *pBin = m_Bin.GetBinShader(szName, false, 0);
  if (!pBin)
    return false;
  if (bUpdateCRC)
  {
    uint32 nCRC32 = pBin->ComputeCRC();
    if (nCRC32 != pBin->m_CRC32)
    {
			FXShaderBinValidCRCItor itor = gRenDev->m_cEF.m_Bin.m_BinValidCRCs.find(pBin->m_dwName);
			if (itor == gRenDev->m_cEF.m_Bin.m_BinValidCRCs.end())
				gRenDev->m_cEF.m_Bin.m_BinValidCRCs.insert(FXShaderBinValidCRCItor::value_type(pBin->m_dwName, false));

      m_Bin.DeleteFromCache(pBin);
      pBin = m_Bin.GetBinShader(szName, false, nCRC32);
      if (!pBin)
        return false;
    }
  }

  // Do not parse techniques for consoles 
#if !defined(XENON) && !defined(PS3)
  if (ShaderNames)
    bRes &= m_Bin.ParseBinFX_Dummy(pBin, *ShaderNames, szName);
#endif

  return bRes;
}

CTexture *CShaderMan::mfParseFXTechnique_LoadShaderTexture (STexSamplerRT *smp, const char *szName, SShaderPass *pShPass, CShader *ef, int nIndex, byte ColorOp, byte AlphaOp, byte ColorArg, byte AlphaArg)
{
  CTexture *tp = NULL;
  if (!szName || !szName[0] || gRenDev->m_bShaderCacheGen) // Sampler without texture specified
    return NULL;
  if (szName[0] == '$')
	{
    tp = mfCheckTemplateTexName(szName, (ETEX_Type)smp->m_eTexType);
		if(tp)
			tp->AddRef();
	}
	else
		smp->m_nTexFlags |= FT_DONT_STREAM | FT_DONT_RESIZE;	// disable streaming for explicitly specified textures
  if (!tp)
  {
    tp = mfTryToLoadTexture(szName, smp, smp->GetTexFlags(), smp->m_eTexType);
  }

  return tp;
}
